Discord Visual Refresh Fixes

1) Removes the useless title bar. 2) Centers the chatbox with the userbox. 3) Moves Inbox to its old location.

// ==UserScript==
// @name         Discord Visual Refresh Fixes
// @namespace    http://tampermonkey.net/
// @license      CC0-1.0
// @version      0.2.0
// @description  1) Removes the useless title bar.  2) Centers the chatbox with the userbox.  3) Moves Inbox to its old location.
// @author       20kdc, kimbjo
// @match        https://discordapp.com/*
// @match        https://discord.com/*
// @grant        none
// ==/UserScript==

/*
Written by 20kdc
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/

// Since iterating through the entire DOM would be performance suicide,
//  let's try to detect classes in ANY OTHER WAY.
var dragonequus;
dragonequus = {
    version: 6.0,
    getAllClassesLen: 0,
    getAllClassesCache: [],
    getAllClasses: function () {
        var sheets = document.styleSheets;
        if (sheets.length == dragonequus.getAllClassesLen) {
            return dragonequus.getAllClassesCache;
        }
        var workspace = [];
        var seen = {};
        for (var k = 0; k < sheets.length; k++) {
            var sheet = sheets[k];
            for (var k2 = 0; k2 < sheet.cssRules.length; k2++) {
                var rule = sheet.cssRules[k2];
                if (rule.type == CSSRule.STYLE_RULE) {
                    // .A:I .B:I, .A .B
                    var majors = rule.selectorText.split(",");
                    for (var k3 = 0; k3 < majors.length; k3++) {
                        var minors = majors[k3].split(" ");
                        for (var k4 = 0; k4 < minors.length; k4++) {
                            // Minor starts off as say .A:B
                            var minor = minors[k4];
                            // Must be class
                            if (!minor.startsWith("."))
                                continue;
                            // Cut off any : and remove .
                            var selectorBreak = minor.indexOf(":");
                            if (selectorBreak != -1) {
                                minor = minor.substring(1, selectorBreak);
                            } else {
                                minor = minor.substring(1);
                            }
                            if (seen[minor])
                                continue;
                            seen[minor] = true;
                            workspace.push(minor);
                        }
                    }
                }
            }
        }
        dragonequus.getAllClassesLen = sheets.length;
        dragonequus.getAllClassesCache = workspace;
        return workspace;
    },
    isValidDC: function (obfuscated, real) {
        if (!(obfuscated.startsWith(real + "-") || obfuscated.startsWith(real + "_")))
            return false;
        if (obfuscated.length != real.length + 7)
            return false;
        return true;
    },
    findAllByDiscordClass: function (name) {
        var q = [];
        var q2 = document.querySelectorAll("." + name);
        for (var k2 = 0; k2 < q2.length; k2++)
            q.push(q2[k2]);
        var classes = dragonequus.getAllClasses();
        for (var k in classes) {
            var n = classes[k];
            if (dragonequus.isValidDC(n, name)) {
                q2 = document.querySelectorAll("." + n);
                for (var k2 = 0; k2 < q2.length; k2++)
                    q.push(q2[k2]);
            }
        }
        return q;
    },
    findByDiscordClass: function (name) {
        var all = dragonequus.findAllByDiscordClass(name);
        if (all.length > 0)
            return all[0];
        return null;
    },
    toDiscordClasses: function (name) {
        var classes = dragonequus.getAllClasses();
        var all = [];
        for (var k in classes) {
            var n = classes[k];
            if (dragonequus.isValidDC(n, name))
                all.push(n);
        }
        all.push(name);
        return all;
    },
    toDiscordClass: function (name) {
        return dragonequus.toDiscordClasses(name)[0];
    },
    hasDiscordLoaded: function () {
        return dragonequus.findByDiscordClass("sidebarList") != null;
    },
    onDiscordLoadedCollection: [],
    onDiscordLoaded: function (fn) {
        if (dragonequus.onDiscordLoadedCollection) {
            dragonequus.onDiscordLoadedCollection.push(fn);
        } else {
            fn();
        }
    },
    _discordLoadDetector: setInterval(function () {
        if (dragonequus.hasDiscordLoaded()) {
            clearInterval(dragonequus._discordLoadDetector);
            var dlc = dragonequus.onDiscordLoadedCollection;
            dragonequus.onDiscordLoadedCollection = null;
            for (var i = 0; i < dlc.length; i++) {
                dlc[i]();
            }
        }
    }, 100),
    injectCSSRulesNow: function (rules) {
        var styleElm = document.createElement('style');
        // console.log("dragonequus CSS:", rules);
        document.body.appendChild(styleElm);
        for (var i = 0; i < rules.length; i++)
            styleElm.sheet.insertRule(rules[i], 0);
    },
    injectCSSRules: function (getRules) {
        dragonequus.onDiscordLoaded(function () {
            dragonequus.injectCSSRulesNow(getRules());
        });
    },
    injectCSSForClassScript: function (clazz, css) {
        dragonequus.injectCSSRules(function () {
            var classes = dragonequus.toDiscordClasses(clazz);
            var total = [];
            for (var i = 0; i < classes.length; i++) {
                // This is stupid.
                // This is really, really stupid.
                total.push(".visual-refresh ." + classes[i] + " { " + css + " }");
                total.push("." + classes[i] + " { " + css + " }");
            }
            return total;
        });
    },
};

// --- Detect chatbox bottom margin ---
function adjustChatInputMargin() {
    const rootElement = document.documentElement;
    const densityClass = Array.from(rootElement.classList)
        .find(cls => cls.startsWith('density-'));

    let marginBottom;

    switch (densityClass) {
        case 'density-compact':
            marginBottom = '6.5px';
            break;
        case 'density-default':
            marginBottom = '10.5px';
            break;
        case 'density-cozy':
            marginBottom = '12.5px';
            break;
        default:
            marginBottom = '10.5px';
    }

    dragonequus.injectCSSForClassScript("container", "--custom-chat-input-margin-bottom: " + marginBottom + " !important;");
}

dragonequus.injectCSSForClassScript("bar", "height: 0 !important; min-height: 0 !important; opacity: 0 !important;");
dragonequus.injectCSSForClassScript("base", "grid-template-rows: [top] 0fr [titleBarEnd] 0fr [noticeEnd] 1fr [end];");
dragonequus.injectCSSForClassScript("guilds", "margin-top: 5px;");
dragonequus.injectCSSForClassScript("sidebarListRounded", "border-top-left-radius: 0px !important;");
adjustChatInputMargin();

// Observe for class changes if the density might change dynamically
const observer = new MutationObserver((mutations) => {
    for (let mutation of mutations) {
        if (mutation.type === 'attributes' &&
            mutation.attributeName === 'class') {
            adjustChatInputMargin();
        }
    }
});

observer.observe(document.documentElement, {
    attributes: true,
    attributeFilter: ['class']
});

// --- Add Duplicate Recents Inbox Button ---
// This code creates a duplicate button for the Recents Inbox and mounts it in the toolbar.
// When clicked, it simulates a click on the hidden Recents button (the one with a class containing 'recentsIcon').

(function () {
    // Helper to inject CSS styles.
    function insertCss(css) {
        var style = document.createElement('style');
        style.textContent = css;
        document.head.appendChild(style);
    }

    // Inject styles for our custom Recents button.
    insertCss(`
        #recents-copy-btn {
            position: relative;
            height: 24px;
            width: auto;
            flex: 0 0 auto;
            margin: 0 8px;
            cursor: pointer;
            color: var(--interactive-normal);
        }
    `);

    // Create the custom Recents button.
    function createRecentsButton() {
        var btn = document.createElement('div');
        btn.id = 'recents-copy-btn';
        btn.tabIndex = 0;
        btn.setAttribute('role', 'button');
        btn.setAttribute('aria-label', 'Recents Inbox');
        btn.title = 'Recents Inbox';

        // Using an SVG icon. You can adjust the paths to match the original Recents icon as needed.
        btn.innerHTML = `<svg aria-hidden="false" width="24" height="24" viewBox="0 0 24 24">
            <path fill="currentColor" fill-rule="evenodd" d="M5 2a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V5a3 3 0 0 0-3-3H5ZM4 5.5C4 4.67 4.67 4 5.5 4h13c.83 0 1.5.67 1.5 1.5v6c0 .83-.67 1.5-1.5 1.5h-2.65c-.5 0-.85.5-.85 1a3 3 0 1 1-6 0c0-.5-.35-1-.85-1H5.5A1.5 1.5 0 0 1 4 11.5v-6Z" clip-rule="evenodd" class=""></path>
        </svg>`;

        btn.onclick = function () {
            // Find the hidden original Recents button and trigger its click
            var origParent = document.querySelector('[class^="recentsIcon"]');
            if (origParent) {
                var actualButton = origParent.querySelector('div[role="button"][aria-label="Inbox"]');
                if (actualButton) {
                    actualButton.click();
                }
            }
        };
        return btn;
    }

    // Mount the custom button into the toolbar.
    function mountRecentsButton() {
        var toolbar = document.querySelector('[class^="toolbar"]');
        if (toolbar && !document.getElementById('recents-copy-btn')) {
            var btn = createRecentsButton();
            toolbar.appendChild(btn);
        }
    }

    // Use a MutationObserver to ensure the button stays in the toolbar even if Discord re-renders the DOM.
    var observer = new MutationObserver(function () {
        mountRecentsButton();
    });
    observer.observe(document.body, { childList: true, subtree: true });
    mountRecentsButton();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址