// ==UserScript== // @name X/Twitter - xTweaks UI Enhance // @namespace https://github.com/BD9Max/userscripts // @version 1.1.1 // @description UI enhance tweaks for X / Twitter. Wider central feed area. Sticky (stays on top) profile navigation while scrolling down. Truncate posts texts to 1-line - expand for full text portion. Smaller posts font size. Hide right sidebar. Collapsible control panel. More functionality added later. // @icon https://raw.githubusercontent.com/BD9Max/userscripts/refs/heads/main/media/icons/xtweaks_icon_64.png // @author krbd9max // @license MIT // @match https://*.x.com/* // @match https://*.twitter.com/* // @grant none // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // --- 1. Configuration State (Saves to Browser Storage) --- const config = { truncate: localStorage.getItem('x-mod-truncate') !== 'false', stickyNav: localStorage.getItem('x-mod-sticky') !== 'false', widerFeed: localStorage.getItem('x-mod-wider') !== 'false', smallText: localStorage.getItem('x-mod-smalltext') !== 'false', focusMode: localStorage.getItem('x-mod-focus') === 'true' }; function updateConfig(key, value, styleNode) { localStorage.setItem(key, value); if (value) { document.head.appendChild(styleNode); } else { if (styleNode && styleNode.parentNode) { styleNode.parentNode.removeChild(styleNode); } } } // --- 2. Feature: 12px Global Tweet Text --- const smallTextStyle = document.createElement('style'); smallTextStyle.textContent = ` [data-testid="tweetText"] { font-size: 12px !important; line-height: 18px !important; } `; if (config.smallText) { document.head.appendChild(smallTextStyle); } // --- 3. Feature: 800px Wide Central Feed (default 600px) --- const widerStyle = document.createElement('style'); widerStyle.textContent = ` [data-testid="primaryColumn"] { max-width: 800px !important; width: 800px !important; } [data-testid="primaryColumn"] > div > div > div, [data-testid="cellInnerDiv"] { max-width: 800px !important; width: 100% !important; } [data-testid="primaryColumn"] .r-1ye8kvj { max-width: 800px !important; } `; if (config.widerFeed) { document.head.appendChild(widerStyle); } // --- 4. Feature: Sticky Profile Navigation --- const stickyStyle = document.createElement('style'); stickyStyle.textContent = ` [data-testid="primaryColumn"] > div > div > div > div > div:has(> nav[role="navigation"]) { position: sticky !important; top: 36px !important; z-index: 10 !important; background-color: rgba(0, 0, 0, 0.7) !important; backdrop-filter: blur(12px) !important; border-bottom: 1px solid rgb(47, 51, 54) !important; } `; if (config.stickyNav) { document.head.appendChild(stickyStyle); } // --- 5. Feature: Right Sidebar Focus Mode (Hide Widgets & Narrow Search) --- const focusStyle = document.createElement('style'); focusStyle.textContent = ` [data-testid="sidebarColumn"] { width: 260px !important; } [data-testid="sidebarColumn"] section, [data-testid="sidebarColumn"] aside, [data-testid="sidebarColumn"] [aria-label="Timeline: Trending now"], [data-testid="sidebarColumn"] [aria-label="Timeline: Explore"] { display: none !important; } [data-testid="sidebarColumn"] form[role="search"] { max-width: 220px !important; margin: 0 auto !important; } `; if (config.focusMode) { document.head.appendChild(focusStyle); } // --- 6. Feature: 1-Line Truncation --- const truncateStyle = document.createElement('style'); truncateStyle.textContent = ` /* Container setup */ [data-testid="tweetText"].is-truncated:not(.expanded-tweet) { display: block !important; white-space: nowrap !important; overflow: hidden !important; position: relative !important; cursor: pointer !important; padding-right: 60px !important; box-sizing: border-box !important; } /* The bold "...more" text with an opaque background to block overlap */ [data-testid="tweetText"].is-truncated:not(.expanded-tweet)::after { content: "...more"; position: absolute !important; right: 0 !important; top: 0 !important; bottom: 0 !important; display: flex !important; align-items: center !important; color: #00ba7c !important; /* X Retweet Green */ font-weight: 700 !important; font-size: 12px !important; /* This blocks the text underneath */ background-color: black !important; padding-left: 8px !important; padding-right: 4px !important; /* Creates a slight fade effect on the left edge */ box-shadow: -10px 0 10px black !important; } `; if (config.truncate) { document.head.appendChild(truncateStyle); } const evaluateTruncation = () => { const tweets = document.querySelectorAll('[data-testid="tweetText"]:not(.truncation-checked)'); tweets.forEach(tweet => { if (tweet.clientWidth === 0) return; // Wait until fully rendered tweet.classList.add('truncation-checked'); const originalWhiteSpace = tweet.style.whiteSpace; tweet.style.whiteSpace = 'nowrap'; const overflowsWidth = tweet.scrollWidth > tweet.clientWidth; tweet.style.whiteSpace = originalWhiteSpace; const lineHeight = parseFloat(window.getComputedStyle(tweet).lineHeight) || 24; const overflowsHeight = tweet.offsetHeight > (lineHeight * 1.5); if (overflowsWidth || overflowsHeight) { tweet.classList.add('is-truncated'); } }); }; const observer = new MutationObserver(evaluateTruncation); observer.observe(document.body, { childList: true, subtree: true }); evaluateTruncation(); document.addEventListener('click', function(e) { const tweetText = e.target.closest('[data-testid="tweetText"].is-truncated'); if (tweetText && !tweetText.classList.contains('expanded-tweet')) { e.preventDefault(); e.stopPropagation(); tweetText.classList.add('expanded-tweet'); } }, true); // --- 7. The Control Panel --- function createControlPanel() { if (document.getElementById('customizer-panel')) return; const switchStyle = document.createElement('style'); switchStyle.textContent = ` .xt-switch { position: relative; display: inline-block; width: 34px; height: 20px; flex-shrink: 0; } .xt-switch input { opacity: 0; width: 0; height: 0; } .xt-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: rgb(83, 100, 113); transition: .2s; border-radius: 20px; } .xt-slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: .2s; border-radius: 50%; } .xt-switch input:checked + .xt-slider { background-color: #00ba7c; } .xt-switch input:checked + .xt-slider:before { transform: translateX(14px); } `; document.head.appendChild(switchStyle); const isMinimized = localStorage.getItem('x-mod-panel-min') === 'true'; const panel = document.createElement('div'); panel.id = 'customizer-panel'; panel.style.cssText = ` position: fixed; bottom: 70px; left: 15px; background-color: black; border: 1px solid rgb(47, 51, 54); border-radius: 12px; z-index: 9999; color: #eff3f4; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 13px; display: flex; flex-direction: column; box-shadow: 0 4px 12px rgba(255,255,255,0.05); width: 250px; overflow: hidden; transition: transform 0.3s ease; transform: ${isMinimized ? 'translateX(-125px)' : 'translateX(0)'}; `; const header = document.createElement('div'); header.style.cssText = ` display: flex; justify-content: ${isMinimized ? 'flex-end' : 'space-between'}; align-items: center; padding: 8px 14px; font-weight: 650; font-size: 13px; cursor: pointer; background-color: rgba(255, 255, 255, 0.05); border-bottom: ${isMinimized ? 'none' : '1px solid rgb(47, 51, 54)'}; transition: background-color 0.2s; `; header.innerHTML = `+xTweaks - UI Enhance`; header.addEventListener('mouseover', () => header.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'); header.addEventListener('mouseout', () => header.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'); const content = document.createElement('div'); content.id = 'customizer-content'; content.style.cssText = ` display: ${isMinimized ? 'none' : 'flex'}; flex-direction: column; gap: 12px; padding: 12px 14px; `; content.innerHTML = ` `; header.addEventListener('click', () => { const currentlyMin = content.style.display === 'none'; if (currentlyMin) { content.style.display = 'flex'; header.style.borderBottom = '1px solid rgb(47, 51, 54)'; header.style.justifyContent = 'space-between'; document.getElementById('panel-extra-text').style.display = 'inline'; document.getElementById('panel-toggle-icon').style.display = 'block'; document.getElementById('panel-toggle-icon-plus').style.display = 'none'; panel.style.transform = 'translateX(0)'; localStorage.setItem('x-mod-panel-min', 'false'); } else { content.style.display = 'none'; header.style.borderBottom = 'none'; header.style.justifyContent = 'flex-end'; document.getElementById('panel-extra-text').style.display = 'none'; document.getElementById('panel-toggle-icon').style.display = 'none'; document.getElementById('panel-toggle-icon-plus').style.display = 'block'; panel.style.transform = 'translateX(-125px)'; localStorage.setItem('x-mod-panel-min', 'true'); } }); panel.appendChild(header); panel.appendChild(content); document.body.appendChild(panel); document.getElementById('toggle-truncate').addEventListener('change', (e) => updateConfig('x-mod-truncate', e.target.checked, truncateStyle)); document.getElementById('toggle-sticky').addEventListener('change', (e) => updateConfig('x-mod-sticky', e.target.checked, stickyStyle)); document.getElementById('toggle-wider').addEventListener('change', (e) => updateConfig('x-mod-wider', e.target.checked, widerStyle)); document.getElementById('toggle-smalltext').addEventListener('change', (e) => updateConfig('x-mod-smalltext', e.target.checked, smallTextStyle)); document.getElementById('toggle-focus').addEventListener('change', (e) => updateConfig('x-mod-focus', e.target.checked, focusStyle)); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createControlPanel); } else { createControlPanel(); } })();