this post was submitted on 15 Jun 2023
43 points (97.8% liked)

Lemmy Plugins and Userscripts

375 readers
1 users here now

A general repository for user scripts and plugins used to enhance the Lemmy browsing experience.

Post (or cross-post) your favorite Lemmy enhancements here!

General posting suggestions:

Thanks!

founded 1 year ago
MODERATORS
 

Wanted to do this for a while. Did it today instead of sleeping.

Screenshot:

You can install it from here: https://greasyfork.org/en/scripts/468948-user-details-on-hover

Link to GitHub repo: https://github.com/lemmygod/lemmy-hovercards/tree/main

Or you can copy-paste the following code:

::: spoiler click here to view code.

// ==UserScript==
// @name         User Details on Hover
// @namespace    http://tampermonkey.net/
// @version      0.12
// @description  Show user details on hover
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
  "use strict";
  const isLemmy =
    document.head.querySelector("[name~=Description][content]").content ===
    "Lemmy";
  if (!isLemmy) return;
  // Inject styles for the user card
  function main() {
    const style = document.createElement("style");
    style.innerHTML = `
  .user-card {
    position: absolute;
    display: none;
    width: 350px;
    background-color: #242424;
    color: white;
    padding: 15px;
    border-radius: 10px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1000;
    grid-gap: 10px;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.4;
  }

  .user-card .header {
    display: flex;
    align-items: center;
    margin-bottom: 10px;
  }

  .user-card img {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border-radius: 50%;
    margin-right: 15px;
  }

  .user-card .username {
    font-size: 1.3em;
    font-weight: bold;
  }

  .user-card .instance {
    font-size: 0.8em;
    color: #888;
  }

  .user-card .body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-gap: 10px;
  }

  .user-card .key {
    font-weight: bold;
  }

  .user-card .value {
    color: #ddd;
    margin-top: 10px;
  }

  .user-card .bio {
    grid-column: 1 / -1;
    font-style: italic;
  }`;
    document.head.appendChild(style);

    // Create the user card
    const userCard = document.createElement("div");
    userCard.classList.add("user-card");
    userCard.id = "user-card";
    document.body.appendChild(userCard);

    let timer;
    // Find all user links
    const userLinks = document.querySelectorAll('a.text-info[href*="/u/"]');
    userLinks.forEach((userLink) => {
      userLink.setAttribute("title", "");
      // When mouse enters, show the user card
      userLink.addEventListener("mouseenter", async (event) => {
        const username = userLink.href.split("/u/")[1];

        // Fetch user details
        const userInfo = await getUserInfo(username);

        // Format the date
        const date = new Date(userInfo.creationDate);
        const formattedDate = `${date.getFullYear()}/${String(
          date.getMonth() + 1
        ).padStart(2, "0")}/${String(date.getDate()).padStart(2, "0")}`;

        // Update the user card
        userCard.innerHTML = `
              <div class="header">
                  <img src="${
                    userInfo.profilePicture ||
                    `https://api.dicebear.com/6.x/identicon/svg?seed=${username}`
                  }" alt="User avatar">
                  <div>
                      <div class="username">${
                        userInfo.name || username.split("@")[0]
                      }</div>
                      <a href="https://${
                        userInfo.instance
                      }/u/${username}" class="instance">${username}${
          username.indexOf("@") === -1 ? "@" + userInfo.instance : ""
        }
                      </a>
                  </div>
              </div>
              <div class="body">
                  <div><span class="key">ID:</span> <span class="value">${
                    userInfo.id
                  }</span></div>
                  <div style="display:flex; flex-direction: column; gap: 3px"><span class="key">
                    <svg class="icon"><use xlink:href="/static/assets/symbols.svg#icon-cake"></use><div class="sr-only"><title>cake</title></div></svg>
                    Cake Day:</span> <span class="value">${formattedDate}</span></div>
                  <div><span class="key">Posts:</span> <span class="value">${
                    userInfo.post_count
                  }</span></div>
                  <div><span class="key">Comments:</span> <span class="value">${
                    userInfo.comment_count
                  }</span></div>
                  <div><span class="key">Post Score:</span> <span class="value">${
                    userInfo.post_score
                  }</span></div>
                  <div><span class="key">Comment Score:</span> <span class="value">${
                    userInfo.comment_score
                  }</span></div>
                  ${
                    userInfo.bio ? `<div class="bio">${userInfo.bio}</div>` : ""
                  }
              </div>`;

        // Show the user card at the cursor
        const rect = userLink.getBoundingClientRect();
        userCard.style.left = `${window.pageXOffset + rect.left}px`;
        userCard.style.top = `${window.pageYOffset + rect.bottom + 5}px`;
        // setTimeout(() => {
        if (userLink.querySelector(":hover")) {
          userCard.style.display = "block";
        }
        // }, 250);
        timer = setTimeout(() => {
          // check if username is not being hovered anymore after 150ms, after which point we must change display to none
          if (!userLink.querySelector(":hover")) {
            userCard.style.display = "none";
          }
        }, 150);
      });

      // When mouse leaves, hide the user card after a slight delay
      userLink.addEventListener("mouseleave", () => {
        // after a slight delay, delete the node
        timer = setTimeout(() => {
          // delete the node
          // userCard.parentElement.removeChild(userCard);
          userCard.style.display = "none";
        }, 250);
        setTimeout(() => {
          // check if both are unhovered after 260ms, and if that's the case, removeChild anyway
          if (!userCard.parentElement) return;
          if (!userCard.querySelector(":hover")) {
            // userCard.parentElement.removeChild(userCard);
            userCard.style.display = "none";
          }
        }, 250);

        // timer = setTimeout(() => {
        //   userCard.style.display = "none";
        // }, 250);
      });
    });

    userCard.addEventListener("mouseenter", () => {
      clearTimeout(timer);
    });

    userCard.addEventListener("mouseleave", () => {
      userCard.style.display = "none";
      // userCard.parentElement.removeChild(userCard);
    });

    // Fetch user info from the API
    async function getUserInfo(userName) {
      const instanceName = location.href.split("/")[2];
      const response = await fetch(
        `https://${instanceName}/api/v3/user?username=${userName}`,
        {
          method: "GET",
          headers: {
            "Content-Type": "application/json",
          },
        }
      );
      const user = await response.json();
      const {
        published: creationDate,
        avatar: profilePicture,
        bio,
        display_name: name,
        name: username,
        id,
        banner,
      } = user.person_view.person;
      const { comment_count, comment_score, post_count, post_score } =
        user.person_view.counts;

      return {
        creationDate,
        profilePicture,
        bio,
        name,
        username,
        id,
        banner,
        instance: instanceName,
        comment_count,
        comment_score,
        post_count,
        post_score,
      };
    }
  }

  // detect react changed url but didn't reload the page by checking for url change
  var oldHref = document.location.href;
  setInterval(function () {
    if (document.location.href !== oldHref) {
      oldHref = document.location.href;
      // Wait for the page to load
      setTimeout(main, 1000);
      console.log("url changed!");
    }
  }, 500);

  // run on page load
  main();
})();
top 30 comments
sorted by: hot top controversial new old
[–] Limeey 2 points 1 year ago (1 children)

I see some issues, can I contribute? Pop this on a git and I'll make a PR with what I see. Particularly, I see you prefetch the info for the userlist on page load, which is problematic. I think we can do better.

Thanks for building this! Love the concept. Really great idea that I was just thinking is sorely missing.

[–] [email protected] 1 points 1 year ago (1 children)

made a new github account today to post stuff like this

made the repo, here u go: https://github.com/lemmygod/lemmy-hovercards/tree/main

i am planning on improving a lot of things but i'm so busy with work. You're welcome to make issues, PRs and stuff.

[–] Limeey 1 points 1 year ago (1 children)

Awesome. I too am a bit busy, but I'll take a look and start playing with it. We can def knock this outta the park, and then honestly we're so close to that RES experience I've been missing lol

[–] [email protected] 1 points 1 year ago (1 children)

btw if you're playing w it and have a few extra mins, im planning on adding buttons to send msg, block & perhaps even open in local instance.

something i just realized a couple of days ago is that lemmy ui uses bootstrap and i didn't leverage this in the component i made, not that i know much bootstrap but some consistency and contrast would not suck. i'll stop being so busy in a couple of weeks tho so meanwhile that's that.

[–] Limeey 1 points 1 year ago

I don't think I'll worry too much about revising your styling toward bootstrap and instead focus on logic improvements and feature addition. We can refactor styling later - if what is there works then I see no need to spend time on that. I did notice you were appending styling to the head instead of using the GM functions, but tbh I'm not positive those are available across all implementations like violentMonkey and the rest.

[–] [email protected] 2 points 1 year ago (1 children)

I am quite surprised, this works on my iPad as well not just my Linux laptop!

Thank you for the user script!

P.s. If you need the Safari Mobile extension it can be found on the App Store as well as GitHub and is GPL licensed

[–] [email protected] 2 points 1 year ago (1 children)

I didn't know you u guys had extensions in iOS browsers! First time I see that. You could install an adblocking user script maybe? I thought iOS was ad hell. Gives me a bit of hope.

[–] fperson 1 points 1 year ago

You could install an adblocking user script maybe

You can! Ghostery and Adguard are available for Safari. Also, lots of userscripts :)

[–] TCGM 2 points 1 year ago (1 children)

Please post this to greasyfork

[–] [email protected] 1 points 1 year ago
[–] 0485919158191 2 points 1 year ago* (last edited 1 year ago) (2 children)

This is great! Thanks! Could you make it work on self as well?

[–] [email protected] 4 points 1 year ago

:D

just updated it to remove something

may do more updates 2moro

glad u liked it

[–] [email protected] 2 points 1 year ago* (last edited 1 year ago) (1 children)

more updates happened, reinstall

it works on self, i don't know why you think it doesn't? but it didn't handle url changes at all, that is fixed now.

[–] [email protected] 2 points 1 year ago (1 children)

got an extra })(); at the very bottom. no biggie

[–] [email protected] 2 points 1 year ago (1 children)

lmao my bad :D ty for noticing, deleted that line

[–] [email protected] 2 points 1 year ago (1 children)
[–] [email protected] 2 points 1 year ago* (last edited 1 year ago) (1 children)

<3

I always kept hovering usernames expecting a card to come out. After a week of doing that, I had to make it happen. It's still missing a few things. I'm glad you like it. Hopefully it'll improve over time.

Lmk if you find any actionable bugs. The only one I can think of rn is reading in regular intervals if the mouse is on a card or username and if not, closing it cuz it sometimes gets stuck open at a random spot of the screen for no reason.

possible improvements: add Send Message button, a Block button, a link to local instance and their own instance if different.

[–] [email protected] 1 points 1 year ago (2 children)

I think I fixed the getting stuck open problem (at least for me). I added this at the end of the mouseenter setup function around line 152.

if (!userCard.querySelector(":hover") && !userLink.querySelector(":hover")) {
  userCard.style.display = "none";
}

"If mouse is gone by the time we're ready, then hide."

[–] [email protected] 2 points 1 year ago

I fixed this problem with an update. Seems to work perfectly now.

[–] [email protected] 1 points 1 year ago

didn't solve it for me 😥 i can't debug for now due to reasons, will see if i get it fixed soonish

[–] 1337tux 2 points 1 year ago* (last edited 1 year ago) (1 children)

Thank you, this is sooooooo good. Absolutely loving it :)

[–] [email protected] 3 points 1 year ago

:) just added it to greasyfork. I'm glad you like it. Hopefully I have time to improve it later.

[–] [email protected] 2 points 1 year ago

I love it ! Thank you !

[–] [email protected] 1 points 1 year ago

asked ChatGPT to make an intro cuz why not:

Bringing User Details to Your Fingertips: The New Lemmy User Hover Card

For some time now, I've had an idea percolating in the back of my mind. I wanted to make browsing Lemmy, the open-source, federated link aggregation community, a bit more efficient and user-friendly. Well, I'm delighted to announce that I've finally turned that idea into a reality. Today, I present to you the new and improved Lemmy User Hover Card.

The Lemmy User Hover Card is a handy userscript, designed to streamline your Lemmy browsing experience. In essence, it allows you to view detailed information about a user simply by hovering over their username.

Functionality

This script works by listening for your mouse movements. When you hover over a user's username, the script fetches the user's information, including their name, username, ID, bio, instance, profile picture, and some usage statistics such as the number of posts and comments they've made. This information is then neatly formatted into a small, convenient pop-up card that appears next to the cursor.

Design and User Experience

Understanding the importance of design and user experience, special attention has been paid to these aspects. The user card follows a simple, clean design, with a dark-themed color scheme that is easy on the eyes. Information is presented in a grid layout for better readability, and different typographic styles are used to create a clear visual hierarchy between different elements.

The card also ensures a seamless user experience. The card appears immediately when you hover over a username but doesn't disappear instantly when the cursor leaves the username. Instead, there's a short delay that allows you to move your cursor onto the card to view the information at your leisure.

Lastly, the user's instance is clickable, allowing you to easily visit their instance.

How to Use

To use the Lemmy User Hover Card, you'll need to have a userscript manager like Tampermonkey installed in your browser. Then, you can simply add the script to your manager and it will automatically start working whenever you browse Lemmy.

In summary, the Lemmy User Hover Card is an easy-to-use, efficient tool that can greatly enhance your Lemmy browsing experience. So why wait? Give it a try and let us know what you think!

[–] miked 1 points 1 year ago (3 children)

I found the card staying up too long and then staying up until clicked on new page.

Changing delay from 400 to 200 seems to make it better.

[–] [email protected] 2 points 1 year ago (1 children)

I made an update. It 100% fixes this, as far as I have tested!! It's awesome. I was getting really annoyed and I'm now really happy :D 😀

[–] miked 1 points 1 year ago (1 children)
[–] miked 1 points 1 year ago* (last edited 1 year ago)

0.13 doesn't work properly with 0.3 of this script enabled -

https://lemmy.world/post/200550

edit - I will test further with that script disabled. I'm on FF 114.0.2 64 bit.

[–] [email protected] 2 points 1 year ago

btw u dont need to click anywhere u just need to re-hover the card and unhover it and it disappears cuz there's also an unhover trigger on the cards

actually the problem why these cards dont disappear is bc there is no disappear trigger if by the time the card appears, both the username and the card are not hovered.

[–] [email protected] 2 points 1 year ago

thx for the tip, i'll try it that way and see if it improves my experience :)

load more comments
view more: next ›