-
-
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(); | |
| })(); |
@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
could you do this for twitter?