-
-
Save c6p/463892bb243f611f2a3cfa4268c6435e to your computer and use it in GitHub Desktop.
| // ==UserScript== | |
| // @name Reddit Multi Column | |
| // @namespace https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e | |
| // @version 0.2.6 | |
| // @description Multi column layout for reddit redesign | |
| // @author Can Altıparmak | |
| // @homepageURL https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e | |
| // @match https://www.reddit.com/* | |
| // @match https://new.reddit.com/* | |
| // @grant none | |
| // @downloadURL https://update.greasyfork.org/scripts/371490/Reddit%20Multi%20Column.user.js | |
| // @updateURL https://update.greasyfork.org/scripts/371490/Reddit%20Multi%20Column.meta.js | |
| // ==/UserScript== | |
| /* jshint esversion: 6 */ | |
| (function() { | |
| 'use strict'; | |
| const MIN_WIDTH = 400; | |
| const COLUMNS = 4; | |
| let columns = COLUMNS; | |
| let cleanup = null; | |
| let parent = null; | |
| const cardIcon = () => document?.querySelector('shreddit-sort-dropdown[header-text="View"]')?.shadowRoot?.querySelector('svg'); | |
| const shouldClean =(icon) => icon === undefined ? false : icon.getAttribute('icon-name') !== "view-card-outline"; | |
| cleanup = shouldClean() | |
| let postMap = new Map() | |
| const indexOfSmallest = function (a) { | |
| let lowest = 0; | |
| for (let i = 1; i<a.length; i++) { | |
| if (a[i] < (a[lowest]-1)) lowest = i; | |
| } | |
| return lowest; | |
| }; | |
| const makeLayout = function(changes=[]) { | |
| if (cleanup) return; | |
| if (!parent) return; | |
| if (parent.style.position !== "relative") { | |
| document.querySelector("main").style.maxWidth = "100%"; | |
| const mainContainer = document.querySelector("div.main-container"); | |
| mainContainer.className = [...mainContainer.classList].filter(c => !c.includes(":grid-cols-")).join(" ") // make wide | |
| document.querySelector("div.subgrid-container").classList.remove("m:w-[1120px]") // make wide | |
| document.getElementById("right-sidebar-container").style.display = "none" // hide sidebar | |
| parent.style.position = "relative" | |
| } | |
| const cols = Math.floor(parent.offsetWidth / MIN_WIDTH); | |
| columns = cols; | |
| const WIDTH = Math.floor((100-columns)/columns); | |
| const nodes = [...parent.querySelectorAll("article, shreddit-ad-post, faceplate-partial").values()] | |
| for (const article of nodes) { | |
| const key = article.ariaLabel | |
| if (key === null) /* faceplate-partial */ { | |
| } else if (key in postMap) { | |
| const post = postMap[key] | |
| if (post.height !== article.offsetHeight) { | |
| post.height = article.offsetHeight | |
| } | |
| } else { | |
| postMap.set(key, {height:article.offsetHeight, col:0, top:0}) | |
| } | |
| } | |
| let tops = Array(columns).fill(0); | |
| for (const post of postMap.values()) { | |
| post.col = indexOfSmallest(tops) | |
| post.top = tops[post.col] | |
| tops[post.col] += post.height | |
| } | |
| const height = Math.max(...tops) | |
| if (height) { | |
| parent.style.height = height + 500 + "px" | |
| } | |
| for (const article of nodes) { | |
| const key = article.ariaLabel | |
| const {col, top} = postMap.get(key) ?? {col:0, top:tops[0]} | |
| article.setAttribute("style", cleanup ? "" : `position:absolute; width:${WIDTH}%; top:${top}px; left:${col*(WIDTH+1)}%`) | |
| } | |
| for (const batch of parent.querySelectorAll("faceplate-batch").values()) { | |
| if (!batch.style.height) { | |
| batch.style.height = [...batch.childNodes].reduce((height,c) => height + c.clientHeight, 0) + "px" | |
| } | |
| } | |
| }; | |
| const setLayout = function(changes, observer) { | |
| const c = shouldClean(cardIcon()); | |
| if (c !== cleanup) { | |
| cleanup = c; | |
| window.requestAnimationFrame(makeLayout) | |
| } | |
| }; | |
| const requestLayout = () => window.requestAnimationFrame(makeLayout) | |
| const pageChange = new MutationObserver(requestLayout); | |
| window.addEventListener('resize', requestLayout); | |
| window.addEventListener('scrollend', requestLayout); | |
| const layoutSwitch = new MutationObserver(setLayout); | |
| const watch = function(changes, observer) { | |
| postMap = new Map() | |
| parent = document.querySelector("article + hr + faceplate-partial").parentNode | |
| if (parent === null) return; | |
| pageChange.observe(parent, {childList: true}); | |
| const timeout = setTimeout(() => { | |
| const icon = cardIcon(); | |
| if (icon !== undefined) { | |
| clearTimeout(timeout); | |
| layoutSwitch.observe(icon, {attributes: true}); | |
| } | |
| }) | |
| window.requestAnimationFrame(makeLayout); | |
| }; | |
| const apply = new MutationObserver(watch); | |
| const app = document.querySelector("shreddit-app") | |
| apply.observe(app, {attributes: true}); | |
| watch(); | |
| })(); |
It seems to be working for me. @elmonteanalogo could you share a subreddit that it does not work, so I can check?
It seems to be working intermitently, it didn't work yesterday but it worked this morning. Not working right now though, in any subreddit or anywhere in the website. Been using it for about a year and its the first time it gives me issues. but I guess it could be on my end, I havent downloaded a different browser to test (I use yandex browser)
Maybe reddit is doing A/B testing with the layout, breaking the script. I can't reproduce for now.
could you do this for twitter?
@dmax511 I've looked into it, but Twitter is cycling element content with scroll position. It is possible, however very hard, with this approach. So I can't make any promises.
ok thanks for looking into it
it doesn't seem to work anymore. Is there a fix for it ?
it doesn't seem to work anymore. Is there a fix for it ?
I started using this userscript Reddit 2023 Ui Revert to forward www.reddit.com to new.reddit.com, then add:
// @match https://new.reddit.com/*
to the top of Reddit Multi Column script and it will work again
@c6p good job on the update, I installed it from Greasyfork
@c6p Awesome ! Thank you, the design is pretty neat ! And the performance seems to be better than before ♥
Hey this might just be a "me" thing but this is so close to doing what I want BUT I'm having this issue where, as I scroll down my feed, each post will swap places around on the screen so that one second a post is in the right column and then the next it's in center (I have 3 columns). This gets confusing very quickly with how often they switch places, in that I'll see a post I want to click but by the time the page "settles" it'll be shifted to a different part of the page. any ideas?
as I scroll down my feed, each post will swap places around on the screen so that one second a post is in the right column and then the next it's in center (I have 3 columns).
+1 having same issue
@lolDayus @drhouse noted. While threads are coming, it re-layouts. But since some thread images are not yet loaded, their height changes. So does their position.
When I have the time, I'm going to try to wait until a thread's content is loaded, to make the layout more stable. Or just keep their assigned rows and columns, even if it makes some columns longer than others.
v0.2.1released
- Add new.reddit.com
- Fix left sidebar scrolling
- Fix article jumpiness
v0.2.2 released
- Fix subreddits that use faceplate-batch elements to virtualize loaded articles
v0.2.3
- Fix empty page due to reddit hiding too far away articles
- Fixed: unbalanced columns
Doesn't work anymore
Doesn't work anymore
Yeah, I think there was an update on Reddit's end. It doesn't work across all browsers now.
v0.2.4
- Fix: update
mainelement type
It stopped working
It seems to be working well in Chrome-based browsers now, but not on Firefox-based browsers. Switching from Violentmonkey to Tampermonkey didn't help.
v0.2.5
- Fix: filter-out
:grid-col-classes from main-container to make it wide
v0.2.6
- Fix: ads breaking column layout
this broke today for me