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:

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();
})();
  • God@sh.itjust.worksOPM
    link
    fedilink
    arrow-up
    2
    arrow-down
    1
    ·
    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!