Skip to content

Bluesky Goodie Bag by o_o

Details

Authoro_o

LicenseNo License

Categorybsky

Created

Updated

Size12 kB

Statistics

Learn how we calculate statistics in the FAQ.

Failed to fetch stats.

Description

Adaptation of "Twitter/X Goodie Bag" for Bluesky

Notes

Twitter/X Goodie Bag but for Bluesky! This currently is not 1:1 in functionality with Twitter/X Goodie Bag, but it still has some killer features.

Options

  • πŸ“± - Exclusive to the mobile layout
  • 🚧 - Incomplete, but usable
  • πŸ“œ - Requires the userscript add-on (more details below)

Posts

  • Show like count on button - toggles the count for like buttons.
  • Show repost count on button - toggles the count for repost buttons.
  • Show reply count on button - toggles the count for reply buttons.
  • Expanded like count - toggles the count for the like text above the buttons when you open a post. You can choose to keep just the text for tapping, or just get rid of it all together.
  • Expanded repost count - toggles the count for the repost text above the buttons when you open a post. You can choose to keep just the text for tapping, or just get rid of it all together.
  • Tip: Hide the expanded like and repost count to entirely get rid of the metric bar.

Profile

  • 🚧 πŸ“œ πŸ“± Show more buttons on the top bar upon scroll - makes the follow and more buttons sticky, so you can still access it when scrolling on someone's profile. Similar to Twitter.
    • Issue: doesn't disable itself on desktop
  • 🚧 πŸ“œ πŸ“± Sticky profile details instead of tabs - replaces the profile tabs (posts, replies, media, feeds) with the user's username and handle as you scroll. Similar to Twitter.
    • Issue: doesn't disable itself on desktop
  • πŸ“± Hide top bar on scroll - toggles the top bar hiding as you scroll.
  • πŸ“± Hide bottom bar on scroll - toggles the bottom bar hiding as you scroll.

Image viewer

  • Move buttons to bottom - moves the buttons of the image viewer to the bottom, and prevents tapping anywhere to close. Useful on mobile for when you're zooming in.

Goodie bag

  • πŸ“œ Warn about userscript version - shows a warning if the userscript add-on's version is not compatible with the currently installed userstyle.

Theme compatibility

These have to do with having this userstyle work well with other userstyles that theme Bluesky. These options alone do not theme Bluesky.

If you only have this userstyle installed, you can safely leave these options as the default.

Userscript add-on

Unfortunately, not all that Twitter/X Goodie Bag does is possible on Bluesky with CSS alone. So, this userstyle also comes with an optional userscript that you can install to add more functionality.

You still configure from Stylus. The userscript doesn't have its own special menu to hunt for.

Install userscript

Source code

Source code has over 10K characters, so we truncated it. You can inspect the full source code on install link.
/* ==UserStyle==
@name           Bluesky Goodie Bag
@namespace      dabric.xyz/post/bluesky-goodie-bag
@version        0.2.2
@description    Several tweaks to Bluesky, all disabled by default
@author         dabric
@preprocessor   stylus
@var checkbox show-likes-inline "Posts: Show like count on button" 1
@var checkbox show-retweets-inline "Posts: Show repost count on button" 1
@var checkbox show-replies-inline "Posts: Show reply button count on button" 1
@var select show-likes "Posts: Expanded like count" ["show:Show", "nonum:Hide number", "hide:Hide entirely"]
@var select show-retweets "Posts: Expanded repost count" ["show:Show", "nonum:Hide number", "hide:Hide entirely"]
@var checkbox more-profile-buttons-on-nav "🚧 πŸ“œ πŸ“± Profile: Show more buttons on the top bar upon scroll" 0
@var checkbox show-profile-details-on-nav "🚧 πŸ“œ πŸ“± Profile: Sticky profile details instead of tabs" 0
@var checkbox image-viewer-buttons-on-bottom "Image viewer: Move buttons to bottom" 0
@var checkbox hide-bottom-bar-on-scroll "πŸ“± Navigation: Hide bottom bar on scroll" 1
@var checkbox hide-top-bar-on-scroll "πŸ“± Navigation: Hide top bar on scroll" 1
@var checkbox show-version-warning "πŸ“œ Goodie bag: Warn about userscript version" 1
@var select theme "Theme compatibility: Theme" ["vanilla:Vanilla", "mocha:Catppuccin Mocha", "custom:Custom"]
@var color custom-background-color "Theme compatability: Custom Background" #000
@var color custom-text-color "Theme compatability: Custom Text" #fff
@var color custom-primary-color "Theme compatability: Custom Primary" #208bfe
@var color custom-overlay-button-color "Theme compatability: Custom Overlay Button" rgba(0, 0, 0, 0.47)
==/UserStyle== */

@-moz-document domain("bsky.app") {
  // all of twitter.com
    if theme == "vanilla" {
      // the paranthesis in the selector seeems to conflict
      // with stylus's parser
      
      :root {
        --goodie-primary-color: rgb(32, 139, 254);
      }
      @css {
        /*dark*/
        body[style*="background-color: rgb(0, 0, 0)"] {
          --goodie-background-color: black;
          --goodie-text-color: white;
          --goodie-overlay-button-color: rgba(0, 0, 0, 0.47);
        }
        
        /*dim*/
        body[style*="background-color: rgb(22, 30, 39)"] {
          --goodie-background-color: rgb(22, 30, 39);
          --goodie-text-color: white;
          --goodie-overlay-button-color: rgba(0, 0, 0, 0.47);
        }
        
        /*light*/
        body[style*="background-color: rgb(255, 255, 255)"] {
          --goodie-background-color: white;
          --goodie-text-color: black;
          --goodie-overlay-button-color: rgba(0, 0, 0, 0.47);
        }
      }
    } else if theme == "mocha" {
      :root {
        --goodie-primary-color: #74c7ec;
        --goodie-text-color: #cdd6f4;
        --goodie-background-color: #1e1e2e; 
        --goodie-overlay-button-color: rgba(0, 0, 0, 0.47);
      }
    } else if theme == "custom" {
      :root {
        --goodie-primary-color: custom-primary-color;
        --goodie-text-color: custom-text-color;
        --goodie-background-color: custom-background-color;
        --goodie-overlay-button-color: custom-overlay-button-color;
      }
    }
    
  :root {
    --goodie-addon-version: "0.0.3"
    unless show-version-warning {
      --goodie-hide-version-warning: "true"
    }
  }
  
  
  background-color = var(--goodie-background-color);
  text-color = var(--goodie-text-color);
  overlay-button-color = var(--goodie-overlay-button-color)
  
  //
  // metrics on post buttons
  //
  
  style-inline-metric(testid, variable) {
    unless variable {
      [data-testid={testid}] {
        > div {
          display: none
        }
      }
    }
  }
  
  style-inline-metric("likeBtn", show-likes-inline)
  style-inline-metric("replyBtn", show-replies-inline)
  
  // the repost button dosent have a test id, for some reason. 
  unless show-retweets-inline {
    [data-testid=repostCount] {
      display: none
    } 
  }
  
  //
  // expanded metrics
  //
  
  style-expanded-metric(testid, variable, name) {
   
    if variable == "nonum" {
       [data-testid={testid}] {
          span {
            visibility: hidden;
            overflow: hidden;
            width: 0;
            display: inline-flex;
          }
        
          font-size: 0px !important;
          
          // - capitalize it since there's no number
          // - obscure the count by always being plural
          &::before {
            font-size: 16px;
            content: name;
          }
        }
    } else if variable == "hide" {
      div:has(> [data-testid={testid}]) {  
       display: none;
     }
    }
    
  }
  
  style-expanded-metric("likeCount-expanded", show-likes, "Likes")
  style-expanded-metric("repostCount-expanded", show-retweets, "Reposts")
  
  if show-likes == "hide" and show-retweets == "hide" {
    // just hide the entire toolbar
    div:has(> div > [data-testid={repostCount-expanded}]) {
      display: none;
    }
  }
  
  unless hide-top-bar-on-scroll {
    // topbar
    div:has(> [data-testid=homeScreenFeedTabs]) {
      opacity: 1 !important;
      transform: none !important;
      pointer-events: unset !important;
    }
    
  }
  
  unless hide-bottom-bar-on-scroll {
    
    // nav
    [style*="padding-bottom: 15px"]:has(> div[role=link]) {
      opacity: 1 !important;
      transform: none !important;
      pointer-events: unset !important;
    }
    
    // back to top fab
    button[aria-label="Load new posts"] {
      transform: translateY(-44px) !important;
    }
    
    // compose fab
    button[data-testid="composeFAB"] {
      transform: translateY(-44px) !important;
    }
  }
  
  
  if image-viewer-buttons-on-bottom {
    
    button-height = 44px;
    button-margin = 10px;
    button-area-height = button-height + button-margin * 2
    
    [aria-label="Close image viewer"] {
      --button-area-height: button-area-height;
      pointer-events: none;
      
      max-height: calc(100% - var(--button-area-height));
      
      button {
        pointer-events: all;
        
        top: unset;
        bottom: (button-margin + button-height) * -1;
      }
    }
    
    
    div:has(> [aria-label="Close image viewer"]) { 
      > div:has(button) {
        top: unset;
        bottom: button-margin;
        left: 50%;
        right: unset;
        transform: translateX(-50%)
        
        button {
          margin: 0;
        }
      }
    }
    
    // show alt as a button as well
    div:has(> div[aria-label="Expand alt text"]) {
      margin-bottom: button-area-height;
      
      &:has(> div > [style*="line-clamp"]) {
        * {font-size: 0 !important;}
          margin-bottom: 0;
        position: absolute;
        bottom: button-margin;
        left: 50%;
        transform: translateX(-50%) translateX(-48px)
        padding: 0;
        height: button-height;
        width: button-height;
        align-items: center;
        justify-content: center;
        border-radius: 999999px;
        background-color: overlay-button-color;
        backdrop-filter: blur(10px);
        
        div[aria-label="Expand alt text"] {
          width: 100%;
          height: 100%;
          position: absolute;
        }
        
        &::after {
          content: "ALT";
          font-size: 12px;
          font-weight: 800;
        }
      }
    }
  }
  
  
}

@-moz-document regexp("^\\S+:\\/\\/bsky\\.app\\/profile\\/[^\\/]+$") {
  //
  // show buttons on scroll
  //
  
  if more-profile-buttons-on-nav {
    gap = 10px;
    padding = 8px + 14px;
    button-width = 40px;
    
    
    body-apply-for-children($amount) {
      body:has([data-testid*="UserAvatar-Container-"].r-1v6e3re ~ div > :nth-child({$amount + 1})) {
        [data-testid="TopNavBar"] [data-testid*=follow] {
          margin-left: (gap + button-width) * $amount;
        }
      }  
    }
    
    for num in (1..4) {
      body-apply-for-children(num)
    }
    
    body:has([data-testid="profileHeaderDropdownListAddRemoveBtn"]) {
      overflow: hidden
    }
    

    body.dgb-back-to-top-shown {
    //body {
      
      // a bit of a hack, but it dosen't seem to break anything
      #root > div .css-175oi2r:has([data-testid="profileHeaderDropdownBtn"]) {
        z-index: unset;
      }
      
      
      
      div:has(> div > [data-testid="profileHeaderDropdownBtn"]) {
        
        
        // prevent shifts
        height: 48px;
        
        button(pos) {
            animation: fade-in 100ms;
        
            @keyframes fade-in {
              0%{opacity: 0}
              100%{opacity: 1}
            }
            
            right: padding + (button-width + gap) * pos;
            
        }
            
            
        [data-testid="profileHeaderDropdownBtn"] {
          // solves the dots getting squished
          padding: 0 !important;
          height: 100%;
          width: 100%;
        }
          
          
        [data-testid="profileHeaderEditProfileButton"] {
          div {
            font-size: 0 !important;
            line-height: 0 !important;
            &::after {
              content: "Edit"
              font-size: 14px !important;
              line-height: 14px !important;
            }
          }
          
        }
          
        [data-testid*="followBtn"] {
          // hide text in follow button
          
          div:last-child {  
            display: none;
          }
          
          // center icon
          
          padding: 0 !important;
          display: flex;
          align-items: center !important;
          justify-content: center !important;
          
          div:first-child {
            margin: unset !important;
          }
        }
        
        apply-for-children($amount) {
          &:has(> :nth-child({$amount + 2})) {
            > * {
              position:fixed;
              top: 2px;
              z-index: 2 !important;
              // force...

Reviews

No reviews yet.