Bluesky Enhanced Layout

Customizes the Bluesky website by creating a responsive three-column feed layout, aligning the navigation menus, and hiding unnecessary elements for a cleaner and more streamlined interface.

目前為 2024-12-11 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Bluesky Enhanced Layout
// @namespace    https://gf.qytechs.cn/en/users/567951-stuart-saddler
// @version      1.0
// @description  Customizes the Bluesky website by creating a responsive three-column feed layout, aligning the navigation menus, and hiding unnecessary elements for a cleaner and more streamlined interface.
// @author       Stuart Saddler
// @icon         https://i.ibb.co/3YT8j83/Bluesky-Enhanced-Layout.png
// @license      MIT
// @match        https://bsky.app/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // === 1. Inject Optimized CSS ===
    function injectCSS() {
        const style = document.createElement('style');
        style.textContent = `
            /* 1. Align the Left Navigation Menu */
            nav[role="navigation"] {
                position: fixed !important;
                top: 0 !important;
                left: 0 !important;
                width: 200px !important;
                height: 100vh !important;
                background-color: rgb(22, 30, 39) !important;
                border-right: 1px solid rgb(46, 64, 82) !important;
                overflow-y: auto !important;
                z-index: 1000 !important;
                display: flex !important;
                flex-direction: column !important;
                padding: 20px 0 !important;
                box-sizing: border-box !important;
                -webkit-transform: translateZ(0);
                -moz-transform: translateZ(0);
                transform: translateZ(0);
                will-change: transform;
            }

            /* 2. Style the Left Menu Items */
            nav[role="navigation"] > .css-175oi2r.r-c4unlt.r-pgf20v.r-1rnoaur.r-1xcajam.r-1ki14p2.r-1w88a7h {
                width: 100% !important;
                margin-bottom: 0 !important;
                padding: 0 !important;
            }

            /* 3. Style the Right Menu to be Below the Left Menu */
            nav[role="navigation"] > .css-175oi2r.r-1ipicw7.r-1xcajam.r-1rnoaur.r-pm9dpa.r-196lrry.css-175oi2r > .css-175oi2r {
                width: 100% !important;
                margin-top: 0 !important;
                padding: 0 !important;
                box-sizing: border-box !important;
            }

            /* 4. Adjust the Feed Container to Prevent Overlapping */
            [data-testid="FeedPage-feed"],
            [data-testid="customFeedPage-feed"],
            [data-testid="followingFeedPage-feed"] {
                column-count: 3 !important;
                -webkit-column-count: 3 !important;
                -moz-column-count: 3 !important;
                column-gap: 20px !important;
                -webkit-column-gap: 20px !important;
                -moz-column-gap: 20px !important;
                width: calc(100vw - 200px) !important;
                margin-left: 200px !important;
                padding: 20px !important;
                box-sizing: border-box !important;
                display: block !important;
                overflow: visible !important;
            }

            /* 5. Style Individual Post Cards */
            .css-175oi2r.r-1habvwh {
                display: inline-block !important;
                width: auto !important;
                margin: 0 0 20px !important;
                background: rgb(22, 30, 39) !important;
                border: 1px solid rgb(46, 64, 82) !important;
                border-radius: 8px !important;
                overflow: hidden !important;
                break-inside: avoid !important;
                -webkit-column-break-inside: avoid !important;
                -moz-column-break-inside: avoid !important;
                box-sizing: border-box !important;
                transition: all 0.2s ease-in-out !important;
                max-width: 100% !important;
                min-height: 150px !important; /* Stabilize post height */
            }

            /* Add a loading state for posts */
            .css-175oi2r.r-1habvwh.loading {
                opacity: 0.5 !important;
            }

            /* 6. Hover Effect for Posts */
            .css-175oi2r.r-1habvwh:hover {
                transform: scale(1.02) !important;
            }

            /* 7. Fix Interaction Buttons Container */
            .css-175oi2r.r-18u37iz.r-1wtj0ep {
                padding: 8px !important;
                border-top: 1px solid rgb(46, 64, 82) !important;
            }

            /* 8. Responsive Design: Adjust Layout on Smaller Screens */
            @media (max-width: 1200px) {
                nav[role="navigation"] {
                    width: 150px !important;
                }
                [data-testid="FeedPage-feed"],
                [data-testid="customFeedPage-feed"],
                [data-testid="followingFeedPage-feed"] {
                    width: calc(100vw - 150px) !important;
                    margin-left: 150px !important;
                }
            }

            @media (max-width: 768px) {
                nav[role="navigation"] {
                    position: absolute !important;
                    width: 100% !important;
                    height: auto !important;
                    border-right: none !important;
                    border-bottom: 1px solid rgb(46, 64, 82) !important;
                    flex-direction: row !important;
                    flex-wrap: wrap !important;
                    justify-content: space-between !important;
                    padding: 10px !important;
                }
                [data-testid="FeedPage-feed"],
                [data-testid="customFeedPage-feed"],
                [data-testid="followingFeedPage-feed"] {
                    width: 100% !important;
                    margin-left: 0 !important;
                }
                nav[role="navigation"] > .css-175oi2r.r-1ipicw7.r-1xcajam.r-1rnoaur.r-pm9dpa.r-196lrry.css-175oi2r > .css-175oi2r {
                    width: auto !important;
                    margin-top: 0 !important;
                }
            }

            /* 9. Hide the Bluesky Logo and Feed Choices at the Top */
            .r-33ulu8.r-5laclt.r-13l2t4g.r-1ljd8xs.css-175oi2r {
                display: none !important;
            }

            /* 10. Hide the Specific Div Element */
            .css-175oi2r.r-18u37iz.r-1niwhzg.r-1e084wi {
                display: none !important;
            }

            /* 11. Hide the Additional Div Element */
            .r-1ipicw7.r-bnwqim.css-175oi2r {
                display: none !important;
            }
        `;
        document.head.appendChild(style);
    }

    // === 2. Optimize Event Handling with Event Delegation ===
    function handleInteractions() {
        document.body.addEventListener('click', (e) => {
            const likeButton = e.target.closest('[data-testid*="like-button"]');
            if (likeButton && !likeButton.dataset.handled) {
                likeButton.dataset.handled = 'true';
            }
        }, { capture: true, passive: true });
    }

    // === 3. Stabilize Posts to Prevent Jumping ===
    function stabilizePosts() {
        const feed = document.querySelector('[data-testid="FeedPage-feed"], [data-testid="customFeedPage-feed"], [data-testid="followingFeedPage-feed"]');
        if (!feed) return;

        const posts = feed.querySelectorAll('.css-175oi2r.r-1habvwh');
        posts.forEach(post => {
            // Check if the post has been processed
            if (!post.dataset.stabilized) {
                // Add a loading class temporarily
                post.classList.add('loading');

                // Once the post is fully rendered, remove the loading class
                requestAnimationFrame(() => {
                    post.classList.remove('loading');
                    post.dataset.stabilized = 'true';
                });
            }
        });
    }

    // === 4. Optimize MutationObserver with Debouncing ===
    function setupMutationObserver() {
        const observerOptions = {
            childList: true,
            subtree: true,
        };

        let debounceTimeout;
        const observer = new MutationObserver(() => {
            clearTimeout(debounceTimeout);
            debounceTimeout = setTimeout(() => {
                stabilizePosts(); // Ensure posts stay in their positions
                moveRightMenuIntoNav();
            }, 200); // Debounce delay of 200ms
        });

        observer.observe(document.body, observerOptions);

        return observer;
    }

    // === 5. Improve Element Selection for Reliability ===
    function moveRightMenuIntoNav() {
        try {
            const nav = document.querySelector('nav[role="navigation"]');
            const rightMenu = document.querySelector('[class*="r-1ipicw7"][class*="r-1xcajam"] > .css-175oi2r');

            if (nav && rightMenu && !nav.contains(rightMenu)) {
                requestAnimationFrame(() => nav.appendChild(rightMenu));
            }
        } catch (error) {
            console.error('Error moving right menu into navigation:', error);
        }
    }

    // === 6. Memory Management with Cleanup Function ===
    function setupCleanup(observer) {
        function cleanup() {
            observer.disconnect();
        }

        window.addEventListener('unload', cleanup);
    }

    // === 7. Initialize the Userscript ===
    function init() {
        injectCSS();
        moveRightMenuIntoNav();
        handleInteractions();
        const observer = setupMutationObserver();
        setupCleanup(observer);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

QingJ © 2025

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