LinkedIn Wide Messaging

Changes layout of LinkedIn Messaging to Full Screen for a wider, more immersive experience.

// ==UserScript==
// @name         LinkedIn Wide Messaging
// @namespace    https://github.com/tahatariq19
// @version      1.0
// @description  Changes layout of LinkedIn Messaging to Full Screen for a wider, more immersive experience.
// @author       Taha Tariq
// @match        https://*.linkedin.com/messaging/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    /**
     * Configuration object to hold all selectors and styles.
     * This makes it easy to update the script if LinkedIn changes its class names or IDs.
     */
    const layoutConfig = {
        selectors: {
            rightSidebar: "#messaging .scaffold-layout__aside",
            mainContent: "#messaging .scaffold-layout__inner",
            contentRow: "#messaging .scaffold-layout__row",
            threadList: "#messaging .scaffold-layout__list",
            chatPane: "#messaging .scaffold-layout__detail",
            chatFooter: "footer.msg-form__footer",
            messageOverlay: "#msg-overlay",
            pillButtonRow: "div.msg-conversations-container__title-row:nth-child(2)",
            allPillButtons: ".msg-conversations-container__title-row > div",
            pillDestination: ".msg-search-form",
            mainContainerTrigger: ".msg-s-message-list-container"
        },
        styles: {
            mainContent: "width: 100%",
            contentRow: "grid-template-columns: 100%; margin-top: 5px !important;",
            threadList: "flex: 1",
            chatPane: "flex: 4",
            chatFooter: "padding-top: 10px !important; padding-bottom: 2px !important;",
            messageOverlay: "padding-right: 120px"
        }
    };

    /**
     * A helper function to apply CSS styles to a given element.
     * @param {string} selector - The CSS selector for the target element.
     * @param {string} styleString - The CSS styles to apply.
     */
    function applyStyles(selector, styleString) {
        const element = document.querySelector(selector);
        if (element) {
            element.style.cssText = styleString;
        }
    }

    /**
     * A helper function to remove an element from the DOM.
     * @param {string} selector - The CSS selector for the element to remove.
     */
    function removeElement(selector) {
        const element = document.querySelector(selector);
        if (element) {
            element.remove();
        }
    }

    /**
     * Main function to apply all the visual changes for the wide layout.
     */
    function applyWideLayout() {
        console.log("Applying wide layout for LinkedIn Messaging...");

        // 1. Remove the right sidebar to create space.
        removeElement(layoutConfig.selectors.rightSidebar);

        // 2. Apply styles to expand the main layout components.
        applyStyles(layoutConfig.selectors.mainContent, layoutConfig.styles.mainContent);
        applyStyles(layoutConfig.selectors.contentRow, layoutConfig.styles.contentRow);
        applyStyles(layoutConfig.selectors.threadList, layoutConfig.styles.threadList);
        applyStyles(layoutConfig.selectors.chatPane, layoutConfig.styles.chatPane);
        applyStyles(layoutConfig.selectors.chatFooter, layoutConfig.styles.chatFooter);
        applyStyles(layoutConfig.selectors.messageOverlay, layoutConfig.styles.messageOverlay);

        // 3. Relocate the filter "pill" buttons to the row above.
        const pillDestination = document.querySelector(layoutConfig.selectors.pillDestination);
        const pillButtons = document.querySelectorAll(layoutConfig.selectors.allPillButtons);

        if (pillDestination && pillButtons.length > 0) {
            const destinationParent = pillDestination.parentNode;
            // Using forEach as an alternative to a for...of loop.
            pillButtons.forEach(button => {
                destinationParent.appendChild(button);
            });
        }

        // 4. Remove the old, now-empty row that contained the pill buttons.
        removeElement(layoutConfig.selectors.pillButtonRow);
    }

    /**
     * MutationObserver to watch for dynamic content loading.
     * LinkedIn is a Single-Page Application (SPA), so content is loaded dynamically
     * without full page reloads. This observer waits for the messaging pane to be
     * added to the page before trying to apply our layout changes.
     */
    const observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                for (const node of mutation.addedNodes) {
                    // We only care about element nodes.
                    if (node.nodeType !== 1) continue;

                    // When the main message container appears, apply the layout.
                    if (node.matches(layoutConfig.selectors.mainContainerTrigger)) {
                        applyWideLayout();
                    }
                    
                    // The message overlay sometimes loads after everything else.
                    // We apply its style again just in case it was missed.
                    if (node.matches(layoutConfig.selectors.messageOverlay)) {
                        applyStyles(layoutConfig.selectors.messageOverlay, layoutConfig.styles.messageOverlay);
                    }
                }
            }
        }
    });

    // Start observing the entire document body for changes.
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

})();