Last active
August 12, 2026 05:19
-
-
Save klydeinside/21441df99f4d0f116ee22838295cd76e to your computer and use it in GitHub Desktop.
Twitch userscripts - Following Directory Narrow Grid
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Twitch – Following Directory Narrow Grid | |
| // @namespace https://cody-tools.local | |
| // @version 1.3 | |
| // @description Forces the twitch.tv/directory/following/live grid into 2 or 3 columns so everything stays close to the left instead of spreading across the whole screen, with the hover lift/glow from the Live Follows Grid script. Runs sitewide so it's already active when you arrive via client-side navigation (e.g. the Live Follows Shortcut button), not just on a hard page load of the directory URL. | |
| // @match https://www.twitch.tv/* | |
| // @grant GM_setValue | |
| // @grant GM_getValue | |
| // @updateURL https://gist.githubusercontent.com/klydeinside/21441df99f4d0f116ee22838295cd76e/raw/twitch-following-narrow-grid.user.js | |
| // @downloadURL https://gist.githubusercontent.com/klydeinside/21441df99f4d0f116ee22838295cd76e/raw/twitch-following-narrow-grid.user.js | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| const STYLE_ID = 'lfDirNarrowGridStyle'; | |
| const TOGGLE_ID = 'lfDirNarrowGridToggle'; | |
| const COLS_KEY = 'lfDirColumns'; | |
| function getCols() { | |
| const v = GM_getValue(COLS_KEY, 3); | |
| return v === 2 ? 2 : 3; | |
| } | |
| function setCols(n) { | |
| GM_setValue(COLS_KEY, n); | |
| applyStyle(); | |
| updateToggleLabel(); | |
| } | |
| function applyStyle() { | |
| let style = document.getElementById(STYLE_ID); | |
| if (!style) { | |
| style = document.createElement('style'); | |
| style.id = STYLE_ID; | |
| document.head.appendChild(style); | |
| } | |
| const cols = getCols(); | |
| const pct = (100 / cols).toFixed(4); | |
| style.textContent = ` | |
| .tw-tower { | |
| justify-content: flex-start !important; | |
| } | |
| .tw-tower > div { | |
| box-sizing: border-box !important; | |
| flex: 0 0 ${pct}% !important; | |
| width: ${pct}% !important; | |
| max-width: ${pct}% !important; | |
| } | |
| .tw-tower article { | |
| border-radius: 8px; | |
| transition: | |
| transform 0.18s cubic-bezier(0.16, 1, 0.3, 1), | |
| box-shadow 0.18s cubic-bezier(0.16, 1, 0.3, 1), | |
| border-radius 0.18s ease; | |
| } | |
| .tw-tower article:hover { | |
| transform: translateY(-4px) scale(1.02); | |
| box-shadow: | |
| 0 12px 32px rgba(145,71,255,0.35), | |
| 0 0 0 1px rgba(145,71,255,0.5); | |
| position: relative; | |
| z-index: 2; | |
| } | |
| `; | |
| } | |
| function removeStyle() { | |
| const style = document.getElementById(STYLE_ID); | |
| if (style) style.remove(); | |
| } | |
| function updateToggleLabel() { | |
| const btn = document.getElementById(TOGGLE_ID); | |
| if (btn) btn.textContent = `Grid: ${getCols()} col`; | |
| } | |
| function createToggle() { | |
| if (document.getElementById(TOGGLE_ID)) return; | |
| const btn = document.createElement('button'); | |
| btn.id = TOGGLE_ID; | |
| btn.style.cssText = ` | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| z-index: 999999; | |
| padding: 8px 14px; | |
| background: #9147ff; | |
| color: #fff; | |
| border: none; | |
| border-radius: 9999px; | |
| font-size: 13px; | |
| font-weight: 700; | |
| font-family: Arial, sans-serif; | |
| cursor: pointer; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.35); | |
| `; | |
| btn.onclick = () => setCols(getCols() === 3 ? 2 : 3); | |
| document.body.appendChild(btn); | |
| updateToggleLabel(); | |
| } | |
| function removeToggle() { | |
| const btn = document.getElementById(TOGGLE_ID); | |
| if (btn) btn.remove(); | |
| } | |
| function isFollowingDirectory() { | |
| return location.pathname.replace(/\/+$/, '') === '/directory/following/live'; | |
| } | |
| function tick() { | |
| if (isFollowingDirectory()) { | |
| applyStyle(); | |
| createToggle(); | |
| } else { | |
| removeStyle(); | |
| removeToggle(); | |
| } | |
| } | |
| let tickScheduled = false; | |
| function scheduleTick() { | |
| if (tickScheduled) return; | |
| tickScheduled = true; | |
| requestAnimationFrame(() => { | |
| tickScheduled = false; | |
| tick(); | |
| }); | |
| } | |
| const origPushState = history.pushState; | |
| history.pushState = function (...args) { | |
| origPushState.apply(this, args); | |
| scheduleTick(); | |
| }; | |
| window.addEventListener('popstate', scheduleTick); | |
| const observer = new MutationObserver(scheduleTick); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| tick(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment