Customizes the Bluesky Home feed by creating a responsive three-column feed layout, aligning the navigation menus, and hiding unnecessary elements for a cleaner and more streamlined interface.
目前為
// ==UserScript==
// @name Bluesky Enhanced Layout
// @namespace https://greasyfork.org/en/users/567951-stuart-saddler
// @version 1.1
// @description Customizes the Bluesky Home feed 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();
}
})();