Tweetdeck side-scrolling buttons

Tweetdeck buttons for tabbing left/right

// ==UserScript==
// @name         Tweetdeck side-scrolling buttons
// @namespace    https://mileshouse.neocities.org/
// @version      1.2
// @description  Tweetdeck buttons for tabbing left/right
// @author       You
// @match        https://tweetdeck.twitter.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tweetdeck.twitter.com
// @grant        GM_registerMenuCommand
// @license MIT
// ==/UserScript==

setTimeout(function() { // 2 second pause before running so tweetdeck can load columns
	'use strict';
	var scrollInterval;
	var distance = 0;
	var targetLoc,targetPixel;
	// targetLoc is the current column index to scroll to, targetPixel is the pixel location of that index
	// currLoc,currPixel same things but where the page is currently scrolled to

	var column = document.querySelector("section.column");
	var container = document.querySelector("#container")
	var width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth; // width of columns;assumes all columns are same
	// * if someone has a custom css with variable column width there will be unexpected behavior

	// buttons html (.stream-item gives it coloration so it can be light/dark)
	var inject = '<div class="lr-scroller stream-item"><div class="scroller-left"><</div><div class="scroller-right">></div></div>';

	// css to use when flipped to top
	var topStyle = `
    .lr-scroller {
        height: 50px;
        width: 100%;
        z-index: 2;
        display: flex;
        left: 0px;
        position: sticky;
    }

    .scroller-left, .scroller-right {
        width: 50%;
        height: 100%;
        font-size: 3em;
        text-align: center;
        user-select: none;
		border-right: black 1px solid;
    }
	`;

	// css to use when flipped to bottom
	var bottomStyle = `
	    .lr-scroller {
        height: 50px;
        width: 100%;
        z-index: 2;
        display: flex;
        left: 0px;
        position: fixed;
		bottom: 0;
		border-top: black 1px solid;
    }

    .scroller-left, .scroller-right {
        width: 50%;
        height: 100%;
        font-size: 3em;
        text-align: center;
        user-select: none;
		border-right: black 1px solid;
    }
	`;
	// insert the css and check the cookie for top/bottom
	var styleSheet = document.createElement("style");
	if (window.localStorage.sidescroll == "bottom") {
		styleSheet.innerText = bottomStyle;

	} else {
		styleSheet.innerText = topStyle;
	}
	document.head.appendChild(styleSheet);

	// insert the buttons html
	container.insertAdjacentHTML("afterbegin", inject);

	// events for clicking the buttons and scrolling on them
	document.querySelector(".scroller-left").addEventListener("click", function(){
		width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
		getNextPos(-1);
		startScrolling();
	});
	document.querySelector(".scroller-right").addEventListener("click", function(){
		width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
		getNextPos(1);
		startScrolling();
	});
	document.querySelector(".lr-scroller").addEventListener("wheel", function(e){
		if (e.deltaY < 0){ //scrolling up
			width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
			getNextPos(-1);
			startScrolling();
		}
		else if (e.deltaY > 0) { //scrolling down
			width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
			getNextPos(1);
			startScrolling();
		}
	});

	// updates the target to scroll to
	function getNextPos(x) {
		var currLoc;
		var maxLoc = Math.floor(container.scrollLeftMax/width)+1; // number of scrolling locations plus 1 for the right-most location
		//container.scrollLeft; // current scroll pixel
		currLoc = Math.ceil(container.scrollLeft/width); // index of column currently scrolled to
		if (targetLoc != null) { // if target already exists you need to use that as current location, so if you are clicking the buttons fast it can scroll fast
			currLoc = targetLoc;
		}
		targetLoc = Math.max(currLoc+x, 0); // new target index is left/right 1 index from current location and above 0
		targetLoc = Math.min(targetLoc, maxLoc); // also new target index can't overshoot right
		targetPixel = targetLoc*width; // new target in pixels
		targetPixel = Math.min(targetPixel,container.scrollLeftMax); // if right-most location, make the targ=scrollLeftMax
		// so it doesnt try to overshoot and make a yucky animation
	}

	// yeah we gay keep scrolling
	function startScrolling(){
		if (scrollInterval==null) { // only start new interval if its not already going
			scrollInterval = setInterval(function(){
				var currPixel = container.scrollLeft; // Current Pixel
				distance = targetPixel-currPixel;

				// messy line but it makes it scroll a minimum of 1 pixel unless it's zero
				// if you just do Math.ceil without the 2nd part it will round fractional negative values the wrong way,
				// which will make the interval never reach the terminate condition when it hits -0.
				// the distance/5 part makes it go 20% of the remaining distance per frame,
				// which makes it have a fast->slow smooth animation curve
				container.scrollBy(Math.ceil(Math.abs(distance)/5)*(distance/Math.abs(distance)), 0);

				if (currPixel==targetPixel) { // if reached target, end interval and unset targets
					clearInterval(scrollInterval);
					scrollInterval = null;
					targetLoc = null;
					targetPixel = null;
				}
			}, 1000/60); // interval for 60 fps (1 second divided by 60)
		}
	}

	// this puts the "Flip button" toggle option in the Tamper/Greasemonkey menu
	GM_registerMenuCommand("Flip buttons to top/bottom", function(){
		if (window.localStorage.sidescroll == "bottom") { // flip to top
			window.localStorage.sidescroll = "top"
			styleSheet.innerText = topStyle;

		} else { // flip to bottom
			window.localStorage.sidescroll = "bottom"
			styleSheet.innerText = bottomStyle;
		}
	});

}, 2000);