Reddit CSS

New Design with new functionalities

目前為 2023-12-04 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Reddit CSS
// @namespace    https://www.reddit.com
// @version      6.3
// @description  New Design with new functionalities
// @author       Agreasyforkuser
// @match        https://old.reddit.com/*
// @match        https://www.reddit.com/*
// @match        https://rapidsave.com/*
// @exclude      https://new.reddit.com/*
// @icon         https://www.redditstatic.com/desktop2x/img/favicon/android-icon-192x192.png
// @license      MIT
// @grant        GM_addStyle
// ==/UserScript==


/////////////////// sort by new ////////////////////////////////////////////////////////////////////////

'use strict';
const re = /https?:\/\/(?:www\.|old\.|new\.)?reddit\.com/i;
for (var i=0, l=document.links.length; i<l; i++) {
    if (re.test(document.links[i].href)) {
        var path = document.links[i].pathname;
        if (path === '/' || path.startsWith('/r/')) {
            var pathlen = path.split('/').length - 1 - (path.endsWith('/') ? 1 : 0);
            if ((pathlen <= 2) && (document.links[i].closest('.tabmenu') === null)) {
                document.links[i].href += path.endsWith('/') ? 'new/' : '/new/';
            }
        }
    }
}
//////////////////////////////// over 18 button ///////////////////////////////////////////////////////

const button = document.querySelector('button.c-btn.c-btn-primary[type="submit"][name="over18"][value="yes"]');
if (button) {button.click();}


/////////////////////////////// auto-click download link after opening the rapidsave page ///////////////
const dbutton = document.querySelector('.downloadbutton');
if (dbutton) {
    dbutton.click();
}

///////////////////////////////////////////////////////////////////////////////////////////////////
(function() {
    'use strict';

    // Define the CSS to enlarge the thumbnails and modify the styling
    var customCSS = `

         /* search placeholder text */
         ::-moz-placeholder {color:transparent !important;}

         /* View full thumbnails on search page */
         .search-result :link {display:inline-table !important}

        .email-collection-banner, .email-verification-tooltip, #eu-cookie-policy {display:none !important}

        .infobar.listingsignupbar, .infobar.commentsignupbar {display: none !important;}
        .infobar, .timeout-infobar {border:none}
        .help-hoverable {display:none}
        .reddit-infobar.with-icon {
             min-height: 35px !important;
             padding: 0 0 0 55px !important;
             height: 35px !important;
             }
        .reddit-infobar.with-icon:not(:hover) {
             min-height: 0 !important;
             padding: 0 0 0 55px !important;
             margin: 0 !important;
             height: 9px !important;
             opacity:0 !important
             }

        /* Video Controls for Mobile */
        video::-webkit-media-controls-panel {background: none; opacity:.7}
        video::-webkit-media-controls-overlay-play-button {opacity: 0}

        /* Flair Labels */
        .flairrichtext {border-radius: 0px;border:none}
        .linkflairlabel {border-radius: 0px;border:none}
        .stamp {background: white;border-radius: 0;padding:0}




        /* Buttons */
        button, .preftable select, input[type="submit"] {border-radius:0}

        /* Subreddit Name */
        body.with-listing-chooser #header .pagename {position:inherit; color: white}
        .pagename a {color: black; margin-left:4px; margin-right:4px}
        .pagename {background-color:white; font-variant: normal; border-radius:0px; margin: 0;}


        /* Adjust the size of the thumbnails */

        .thumbnail, .thumbnail img{
            width: 200px !important;
            height: auto !important;
            position: relative;
            margin-bottom: 0;
        }

        /* Visibility of text posts */
        .expando-button.selftext {float:left}
        .expando-button.selftext {height:50px !important;width:200px !important; background-image:none !important;background-color: black !important}


        /* no margin left for expanded media */
        .entry {margin-left:0}

        /* size videos correctly */
        .no-constraints-when-pinned {min-width:0 !important; min-height: 0 !important;}

        /* Videoplayer Background */
        .reddit-video-player-root {background: #0000;}

        /* Video Duration Info */
        .duration-overlay {font-size: 10pt; font-weight: bold;}
        .duration-overlay {border-top-left-radius: 10px; width:auto !important; padding:5px; right:0}


        /* OP indicator */
        .tagline .submitter, .search-result-meta .submitter {color: #228822}

        /* sort menu*/
        .menuarea {border:none}
        .dropdown.lightdrop .selected {text-decoration: none}

        /* Post */
        .thing .title      {font-weight: normal;color: #000; ;margin-bottom: 15px;}
        .subreddit         {font-weight: bold;font-size: larger;color: #000;}
        .link .flat-list   {font-size:larger}
        .link.last-clicked {border: 3px dotted red;}

        /* Text Posts Background*/
        .link .usertext-body .md {background: none; border: 1px solid gray; border-radius: 0}

        /* Post Details */
        .entry .buttons li a {color:#000000c7; font-weight:normal}

        .entry .buttons li       {background: #0000000d}
        .entry .buttons li:hover {opacity:1 !important} //revert graying-out function on hover

        .tagline {color: #8880; margin-bottom: 15px;}
        .tagline .live-timestamp {color: #369}
        .domain {display: none;}
        .reportbtn {display:none}
        .post-crosspost-button {display:none}
        .post-sharing-button {display:none}
        .buttons .give-gold.gold-give-gold {display: none}
        .hide-button {display:none !important}
        .expando-button {opacity: 0.1;float:right}


        /* Header Font Size and Icon */
        #header-bottom-left {font-size: large;}
        #header-img.default-header:not(:hover) {opacity: 0}

        /* Upper Bars */
        #sr-header-area:not(:hover)          {background: none !important; opacity:0.3 }
        #sr-header-area                      {border-bottom: none}
        #sr-header-area .redesign-beta-optin {display:none}
        #sr-more-link                        {background-color: #cee3f8 }

        /* Hide Username */
        .user a:not(:hover) {opacity: 0;}



        .pref-lang {font-weight: normal}
        #header-bottom-right:not(:hover) {background: none; border-radius:0}
        #header-bottom-right {background: white; border-radius:0}
        #header-bottom-right {font-size: larger;}
        #header {border:none}
     


        .separator {color: transparent;}
        #header-bottom-left {margin-top: -10px;}
        a[href="https://old.reddit.com/wiki/"].choice {display: none;}
        .tabmenu li a          {background:none;opacity:0.6;font-weight: normal}
        .tabmenu li a:hover    {background:white}
        .tabmenu li.selected a {opacity:1;font-weight: bold;font-size: x-large; background-color: white; border: none}
        .tabmenu li.selected a {text-transform: uppercase}




        /* Sidebar */
        .sidecontentbox .content {border: none; background: none}
        .sidebox .spacer         {display: none}
        .premium-banner          {display: none}
        .giftgold                {display: none}
        .titlebox .bottom {border:none}
        #searchexpando, .linkinfo, .linkinfo .shortlink input  {border: none}
        .morelink .nub  {display: none}
        .morelink       {border: none; background: #eff7ff;background-image:none}
        .toggle .option {border: none; border-radius:0}
        .c-btn-primary  {border: none; border-radius: 0;}
        .subscription-box:not(:hover) {opacity: 0}


        /* Space between Posts */
        .link {margin-bottom: 0px;}

        /* Expanded Post Margins */
        .expando {margin: 0}

        /* Gallery Buttons */
        .media-gallery .gallery-nav-bar  {font-size:large; display:grid}
        .media-gallery .gallery-nav-next {border:1px solid #336699;background:#eff7ff; float:right !important}
        .media-gallery .gallery-nav-prev {border:1px solid #336699;background:#eff7ff}
        .media-gallery .gallery-nav-back {border:1px solid #336699;background:#eff7ff}
        /*.gallery-navigation {padding: 0px}*/
        .gallery-navigation   {border: none}
        .gallery-nav-disabled {opacity:0 !important}

        /* Rank / Scores */
        .link .rank {display: none}
        .arrow.up {display: none}
        .arrow.down {display: none}

        /* Comment Page */
        .panestack-title { padding-bottom: 0px; border-bottom: none;}
        .commentarea .menuarea {font-size: large;}
        .comment .author {font-size: larger;float:left}
        .comment .expand {font-size: large;float:left; opacity:1;margin: 0 !important;padding: 0 !important; opacity:0}
        .comment .expand {width:6px}
        .comment.collapsed .expand { opacity:1;width:auto}
        .comment .midcol {z-index:9999}
      

        .commentarea > .usertext:not(:hover) {opacity:0.2; height: 18px}

        .commentarea .entry .buttons:not(:hover) {opacity:0;}
        .comments-page #siteTable .thing {display: flex !important;border: none;}
        .comment .tagline {color: #00000069 ; margin-bottom: 15px; text-align:left}
        .comment .child {border-left: dotted 3px #000000}
        .comment .score {font-size: larger}
        .comments-page .arrow.up {display:block}
        .comments-page .arrow.down {display:block}
        .pinnable-content.pinned {background-color: #FFFFFFF7 !important;box-shadow: none !important}
        .reddiquette {display: none}

        /* Bottom Page */
        .footer {display:none}
        .footer-parent {opacity:0}
        .debuginfo {display:none}
        .bottommenu {opacity:0}

        /* promoted posts/ads */
        .link.promotedlink.promoted, .link.promotedlink.external {display:none !important}

        /* submissions */
        .formtabs-content .infobar {border:none}
        .content.submit .info-notice {display: none;}
        #items-required {display: none;}



        /* Navbar */
        .nav-buttons {
         display:table;
         bottom: 0 !important;
         right: 0 !important;
         text-align: center !important;
         border: 3px solid;
         border-color: #cee3f8;
         border-top-left-radius: 15px;
         background-color: #cee3f8;
         font-size: larger;
         z-index: 9998 !important;
         }
        .nextprev a {background:none !important}

         /* Crossposts */
        .crosspost-preview {border-radius: 0 !important}

    `;

    // Add the custom CSS to the page
    GM_addStyle(customCSS);

////////////////////// Remove thumbnails from posts without thumbnails////////////////////////

    function removePostsWithoutImages() {
        var posts = document.querySelectorAll('.thumbnail');
        for (var i = 0; i < posts.length; i++) {
            if (!posts[i].querySelector('img')) {
                posts[i].parentNode.removeChild(posts[i]);
            }
        }
    }
    setInterval(removePostsWithoutImages, 1000);
})();


////////////////////////////////////// comments page //////////////////////////////////

var commentpage = /https:\/\/.*\.reddit\.com\/.*\/comments\/.*/;
if (commentpage.test(window.location.href)) {
    GM_addStyle(`.reportbtn                         {display:block}
                 .post-crosspost-button             {display:block}
                 a.comments                         {display:none}
            /*   .buttons .give-gold.gold-give-gold {display:block}  */
                 .expando-button                    {opacity: 1 }
                 .hide-button                       {display:block !important}

                 a.embed-comment                    {display: none}
            /*   a.bylink                           {display: none}  */


                 .thumbnail,.thumbnail img  {width: 100px !important;height: 100px !important;}
                 #sr-header-area {display:none}

            /* without this voting comments on mobile is impossible */
                 .entry {margin-left:4px}

                 `
                 );

////////////////////////////////// Download Button ////////////////////////////////////


    'use strict';

    function downloadVideo() {
        var postUrl = window.location.href;
        var baseUrl = 'https://rapidsave.com/info?url=';
        var downloadUrl = baseUrl + encodeURIComponent(postUrl);
        window.open(downloadUrl, '_blank');
    }

    function createDownloadButton() {
        var listItem = document.createElement('li');
        listItem.classList.add('reddit-video-download-button');

        var button = document.createElement('button');
        button.innerHTML = 'Download';
        button.style.color = '#000000c7'; //same as .entry .buttons li a
        button.style.background = 'none';
        button.style.border = 'none';
        button.style.fontSize = 'inherit';
        // button.style.borderRadius = '10px';
        // button.style.fontWeight = 'bold';
        button.onclick = downloadVideo;

        listItem.appendChild(button);

        var buttonsList = document.querySelector('ul.buttons');
        if (buttonsList) {
            buttonsList.appendChild(listItem);
        }
    }

    createDownloadButton();


/////////////////////add profile pictures next to comments ///////////////////////

const addAvatars = async (root = document) => {
    Array.from(root.querySelectorAll('.thing:not(.morechildren)')).forEach(async (thing) => {
        if (!thing) return;
        if (thing.hasAttribute('data-reddit-profile-picture')) return;
        const img = document.createElement('img');
        img.classList.add('reddit-profile-picture');
        img.style.height = '22px';
        img.style.width = '22px';
        img.style.float = 'left';
        img.style.margin = '0px';
        thing.insertBefore(img, thing.querySelector('.entry'));
        thing.setAttribute('data-reddit-profile-picture', 1);
        if (!thing.id) return;
        const authorElement = thing.querySelector('.author');
        if (authorElement && authorElement.href) {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', `${authorElement.href}/about.json`);
            xhr.addEventListener('load', async () => {
                if (xhr.status === 200) {
                    try {
                        const profile = JSON.parse(xhr.responseText).data;
                        const ta = document.createElement('textarea');
                        ta.innerHTML = profile.icon_img;
                        img.src = ta.value;
                    } catch (error) {
                        // Error parsing JSON or extracting URL
                        console.error('Error parsing JSON or extracting URL:', error);
                        removeAvatar(img);
                    }
                } else {
                    // Non-200 status, handle error
                    console.error('Error fetching user data:', xhr.status, xhr.statusText);
                    removeAvatar(img);
                }
            });
            xhr.addEventListener('error', () => {
                // Network error
                console.error('Network error while fetching user data.');
                removeAvatar(img);
            });
            xhr.send();
        }
    });
};

const removeAvatar = (imgElement) => {
    if (imgElement && imgElement.parentNode) {
        imgElement.parentNode.removeChild(imgElement);
    }
};

addAvatars();

const mo = new MutationObserver((muts) => {
    muts.forEach((mut) => {
        Array.from(mut.addedNodes).forEach((node) => {
            if (node instanceof HTMLElement) {
                addAvatars();
            }
        });
    });
});
mo.observe(document.body, { childList: true, subtree: true });
};

////////////////////////////// userpage ///////////////////////////////////////////////////////////////////

var userpage = /https:\/\/.*\.reddit\.com\/user\/.*/;
if (userpage.test(window.location.href)) {

    GM_addStyle(`.comment, .content .details {border-bottom: 2px solid #5f99cf !important}`);

    const addProfilePictures = async (root = document) => {
        Array.from(root.querySelectorAll('.pagename')).forEach(async (pagename) => {
            if (!pagename) return;
            if (pagename.hasAttribute('data-reddit-profile-picture')) return;

            const username = pagename.textContent.trim();
            if (!username) return;

            const img = document.createElement('img');
            img.classList.add('reddit-profile-picture');
            img.style.height = '35px';
            img.style.width = '35px';
            img.style.verticalAlign = 'middle';


            pagename.parentNode.insertBefore(img, pagename.nextSibling);

            pagename.setAttribute('data-reddit-profile-picture', 1);

            const xhr = new XMLHttpRequest();
            xhr.open('GET', `https://www.reddit.com/user/${username}/about.json`);
            xhr.addEventListener('load', async () => {
                const profile = JSON.parse(xhr.responseText).data;
                const ta = document.createElement('textarea');
                ta.innerHTML = profile.icon_img;
                img.src = ta.value;
            });
            xhr.send();
        });
    };

    addProfilePictures();

    const mo = new MutationObserver((muts) => {
        muts.forEach((mut) => {
            Array.from(mut.addedNodes).forEach((node) => {
                if (node instanceof HTMLElement) {
                    addProfilePictures(node);
                }
            });
        });
    });

    mo.observe(document.body, { childList: true, subtree: true });
};


//////////////////////////////////////////// red numbers if score is less than one //////////////////////////////////////

if (userpage.test(window.location.href) || commentpage.test(window.location.href)) {
  (function() {
    'use strict';

    // Function to check if the text starts with a "-" or "0"
    function startsWithNegativeSymbolOrZero(text) {
      return text.trim().startsWith('-') || text.trim().startsWith('0');
    }

    // Get all elements with class "score likes"
    var scoreElements = document.querySelectorAll('.score');

    // Iterate over each score element using forEach
    scoreElements.forEach(function(scoreElement) {
      var scoreText = scoreElement.textContent.trim();

      // Check if the score starts with a "-" or "0"
      if (startsWithNegativeSymbolOrZero(scoreText)) {
        // Change the color to red
        scoreElement.style.color = 'red';
        scoreElement.style.fontWeight = 'bold';
      } else if (parseFloat(scoreText) > 1) {
        // Change the color to green
        scoreElement.style.color = 'green';
        scoreElement.style.fontWeight = 'bold';
      }
    });
  })();
}

/////////////////////////grey out comment-buttons if no comments were written /////////////////////////////////


if (!commentpage.test(window.location.href)) {

    'use strict';

    const removeCommentsCount = element => {
        const text = element.textContent.trim();
        if (!isNaN(parseInt(text.charAt(0), 10))) return;
        element.closest('.entry .buttons li').style.opacity = '0.2';
    };

    const commentElements = document.querySelectorAll('a.comments');
    commentElements.forEach(removeCommentsCount);

    const observer = new MutationObserver(mutationsList => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                const newCommentElements = mutation.addedNodes;
                newCommentElements.forEach(node => {
                    if (node instanceof HTMLElement) {
                        const element = node.querySelector('a.comments');
                        if (element) removeCommentsCount(element);
                    }
                });
            }
        }

    });

    observer.observe(document.body, { childList: true, subtree: true });
};

/////////////////////////////////////////////////Thumbnail Click Functionality //////////////////

// Custom CSS for the clicked thumbnail
const customCSS = `
  /* Makes Clicking Easier */
  .thumbnail {z-index:99}

  .thumbnail.clicked {
    width: 80px !important;
    height: 80px !important;
    border-radius: 15px;
    opacity:0.5;
  }

  .thumbnail.clicked img {
    width: 80px !important;
    height: 80px !important;
  }

  .thing.clicked .arrow.up {display: block}
  .thing.clicked .arrow.down {display:block}
`;

function expandPostOnElementClick(element) {
  const expandoButton = element.closest('.thing').querySelector('.expando-button');

  if (expandoButton) {
    expandoButton.click();
  }
}

function handleElementClick(event) {
  event.stopPropagation();
  event.preventDefault();

  const element = event.currentTarget;
  const thumbnail = element.closest('.thumbnail');
  const thing = element.closest('.thing');

  // Check if the thumbnail has the 'clicked' class
  const isClicked = thumbnail.classList.contains('clicked');

  if (isClicked) {
    // Remove the 'clicked' class to revert the changes
    thumbnail.classList.remove('clicked');
    thing.classList.remove('clicked');
  } else {
    // Add 'clicked' class to the thumbnail
    thumbnail.classList.add('clicked');
    thing.classList.add('clicked');
  }

  expandPostOnElementClick(element);
}

function attachClickListenersToElements() {
  const elements = document.querySelectorAll('.thumbnail, img[src*="external-preview.redd.it"]');

  elements.forEach((element) => {
    element.addEventListener('click', handleElementClick);
  });
}

// Add custom CSS styles
GM_addStyle(customCSS);

// Attach click listeners to elements initially
attachClickListenersToElements();

// Create a MutationObserver to monitor the page for changes
const observer = new MutationObserver(() => {
  // Attach click listeners to elements whenever new content is added to the page
  attachClickListenersToElements();
});

// Start observing the document for changes
observer.observe(document, { childList: true, subtree: true });

/////////////////////Toggle Nav-Bar On Scroll /////////////////////////////////////////////////////////////


'use strict';

var navButtons = document.getElementsByClassName('nav-buttons');
if (navButtons.length > 0) {
  var nav = navButtons[0];
  nav.style.position = 'fixed';
}

//var headerHeight = header.offsetHeight;
var lastScrollTop = 0;


window.addEventListener('scroll', function() {
  var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  var windowHeight = window.innerHeight;
  var documentHeight = document.documentElement.scrollHeight;

  if (scrollTop === 0) {
    // Reached the top of the page
    nav.style.opacity = '1';
    nav.style.pointerEvents = 'auto';
    } else {
      // Scrolling up
      nav.style.opacity = '.8';
      nav.style.pointerEvents = 'auto';
    }

  if (scrollTop + windowHeight + 10 >= documentHeight) {
    // Reached the end of the page
    nav.style.opacity = '1';
    nav.style.pointerEvents = 'auto';
    } else {
    if (scrollTop > lastScrollTop) {
      // Scrolling down
      nav.style.opacity = '0';
      nav.style.pointerEvents = 'none';
    } 
  }

  lastScrollTop = scrollTop;
});


/////////////////////////////////////// remove some tabs /////////////////////////////////////////////////

(function() {
    'use strict';

    // Function to remove the elements containing the text "gilded" or "best" from .tabmenu
    function removeGildedAndBestTabs() {
        const tabmenu = document.querySelector('.tabmenu');
        if (!tabmenu) return;

        const tabs = tabmenu.querySelectorAll('a');
        for (let i = 0; i < tabs.length; i++) {
            const tab = tabs[i];
            const tabText = tab.textContent.toLowerCase();
            if (tabText.includes('gilded') || tabText.includes('best')) {
                tab.remove();
            }
        }
    }

    // Call the function to remove the "gilded" and "best" tabs after the page has loaded
    window.addEventListener('load', removeGildedAndBestTabs);
})();

////////////////////////////////////// Subreddit Icon next to Subreddit name /////////////////////////

(function() {
  'use strict';

  function setSubredditIcon() {
    const pagenameLink = document.querySelector('.pagename');
    const subredditIcon = document.createElement('img');
    subredditIcon.style.verticalAlign = 'middle';
    subredditIcon.style.width = 'auto';
    subredditIcon.style.height = '35px';

    const srName = getSrName();


    const srDataUrl = `https://www.reddit.com/r/${srName}/about.json`;
    fetch(srDataUrl)
      .then(response => response.json())
      .then(data => {
        const communityIcon = cleanUpCommunityIcon(data.data.community_icon);
        const iconUrl = communityIcon || data.data.icon_img || data.data.header_img;
        if (!iconUrl || iconUrl.length === 0)
           {
           return;
           }
        subredditIcon.src = iconUrl;
        pagenameLink.parentNode.insertBefore(subredditIcon, pagenameLink.nextSibling);
      })

  }

  function getSrName() {
    const srNameRegex = /https:[/][/](www|old|new)[.]reddit[.]com[/]r[/](\w+)/g;
    const match = srNameRegex.exec(document.location.href);

    return match[2];
  }

  function cleanUpCommunityIcon(url) {
    if (!url || url.length === 0) {
      return url;
    }
    function htmlDecode(input) {
      const doc = new DOMParser().parseFromString(input, 'text/html');
      return doc.documentElement.textContent;
    }
    const decodedUrl = htmlDecode(url);
    return decodedUrl;
  }

  setSubredditIcon();
})();