Badge in Navbar

Hello!

I don’t know if I’m in the right category but I have an idea and want to ask either this is possible or if someone had done this already.

For example I have a “blog” site where every now and then I will post a “new” article.
In the navbar is a button linked to the site.

Is it possible to add a badge (or something similar) to the button with a number of “unread” articles since last visit?

It is just an idea but would be nice (at least for me) if this is possible.

Thank you!

Kind regards

Alex

yes but you have to use mysql. I

HTML you can used the badge component and drag it into your navbar button.

You can find more on positioning here:

With regards to showing the actual number, if you are using a CMS there may be something in the system that is useable.

Post as much information on here how you are creating your articles and someone might be able to help.

Thanks for your reply.

There is no backend or cms or something else, it’s just a normal html site from BSS and the articles are built with divs, columns, etc.

You could try using javascript to store the last time the user was on the site and store it in localstorage, then check to see what articles have been published after the last visit.

When you create a new article you would need to update the publishDate in the articles array

const articles = [
  { publishDate: 1728416433744 },
  { publishDate: 1728416615919 },
  { publishDate: 1728415954441 },

  // ... more articles ...
];

// Function to store the current time in localStorage
function storeLastViewTime() {
  try {
    localStorage.setItem("lastViewTime", Date.now());

//  uncomment the line below
 //  localStorage.setItem('lastViewTime', 1728416342692);


  } catch (error) {
    console.error("Error storing last view time:", error);
  }
}

// Function to get the stored last view time
function getLastViewTime() {
  try {
    return parseInt(localStorage.getItem("lastViewTime") || 0);
  } catch (error) {
    console.error("Error retrieving last view time:", error);
    return 0;
  }
}

// Function to calculate the number of new articles
function countNewArticles(articles, lastViewTime) {
  const currentTime = Date.now();
  return articles.filter(
    (article) =>
      article.publishDate > lastViewTime && article.publishDate <= currentTime
  ).length;
}

// Function to display the badge
function displayBadge(count) {
  //set articlesContainer to be navigation link with class of articles
  const articlesContainer = document.querySelector(".articles");

  //create the badge
  const badgeElement = document.createElement("span");
  badgeElement.textContent = `${count}`;
  badgeElement.classList.add(
    "badge",
    "bg-primary",
    "position-right",
    "position-absolute",
    "top-0",
    "start-100",
    "translate-middle"
  );

  //show the badge
  articlesContainer.appendChild(badgeElement);
}

// Main function to handle everything
function handleNewArticlesBadge() {
  // Store the current time

  // Get the stored last view time
  const lastViewTime = getLastViewTime();
  storeLastViewTime();

  // Assume we have access to all articles here
  // In a real scenario, you'd likely fetch this data from an API
  

  // Calculate the number of new articles
  const newArticleCount = countNewArticles(articles, lastViewTime);

  // Display the badge if not zero
  if (newArticleCount !=0) {
  displayBadge(newArticleCount);
}

}

// Call the main function when the page loads
document.addEventListener("DOMContentLoaded", handleNewArticlesBadge);

In your navbar give the link that you want the badge to display a class of articles.

If you need something to create your publish date timestamps:

Wow, that’s really impressive.
I guess I really need to learn JS.

I have only one question:
Where can you specify which html page should be looked for in the JS file or where do you have to mark the article in the html page so that it is recognized by the JS file?

You don’t need to. When you create a new article, you will need to add the publish date to the array:

const articles = [
  { publishDate: 1728416433744 },
  { publishDate: 1728416615919 },
  { publishDate: 1728415954441 },

  // ... more articles ...
];

Ah ok, now I understand!

Thank you so much!

I don’t know if this is possible but you should release it as a component. :+1:

1 Like

Do I need to uncomment this line and change the timespan every time or do I only need to add a new line at the const articles?

I tried it both ways but I never see the badge.

This js may be better for you and gets rid of needing to update the timestamps array each time.

you can set the first two lines of the code to suit your sites layout

articlesUrl will be set to the url of your articles index page
messageElement will be the element to display the message.

This is based that each article on the articles page has a class of .article

document.addEventListener("DOMContentLoaded", () => {
  const articlesUrl = "articles.html";
  const messageElement = document.getElementById("articlesMessage");

  // Function to fetch the articles page and count the articles
  const checkArticlesCount = async () => {
    try {
      const response = await fetch(articlesUrl);
      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      const parser = new DOMParser();
      const htmlDoc = parser.parseFromString(
        await response.text(),
        "text/html"
      );

      // Count the number of elements with class 'article'
      const currentCount = htmlDoc.querySelectorAll(".article").length;

      // Retrieve the previous count from local storage
      const previousCount = localStorage.getItem("articleCount");

      // Compare the counts and display a message if needed
      if (previousCount) {
        const newArticlesCount = currentCount - previousCount;

         if (newArticlesCount == 0) {
           messageElement.textContent = `There are no new articles since your last visit.`;
         }

        if (newArticlesCount == 1) {
          messageElement.textContent = `There is a new article for you since your last visit.`;
        }

        if (newArticlesCount > 1) {
          messageElement.textContent = `There are ${newArticlesCount} new articles since your last visit.`;
        }
      }

      // Store the current count in local storage
      localStorage.setItem("articleCount", currentCount);
    } catch (error) {
      console.error("Error fetching articles:", error);
    }
  };

  // Check articles count on page load
  checkArticlesCount();
});

Thank you for your work and your help!

But I don’t get it.

Where should I mark the article as an article? Do I need to use the bootstrap component (html 5 article) and wrap it around the complete article (it has divs, etc), or do I need to add .article to each div (every div in the first level is a new article in my case).

And is this right with the articlemessage?

Where should the message appear that there is none, one or more new articles?


article2
article3

here is the bss file so you can see all the structure.

https://dropover.cloud/4917af

I have updated the script and tried to comment as much as possible so you can see what is going on.

1 Like

Thank you very much for your example file.

Now everything is clear to me and I know what you meant.
The example is really great.

2 Likes

One last question:

My Navbar is “fixed to top”.
Of course I could set the “Header->Div with the article count” with a margin under the Navbar or to another location (under my Navbar is a hero banner).

Is there a better way to set it without to move everything?

EDIT:
And if there are no new articles there shouldn’t be show anything.

EDIT:

Please forget my first question.
I will try to show a modal. :slight_smile:

You can have the message appear in any element on your page, just give it an ID of “articlesMessage” (or change the id on line 3 of the JS in the example to suit)

To not show a message when there are no new articles comment out lines 30 and 42 in the JS

The example also includes this CSS, which will hide the message element when it has no contents

#articlesMessage:empty {
  display: none;
}

Thank you for your answer!

After I wrote here yesterday I tried a lot of options ( and saw the css part) on how I will use it and tested many things.

I still can’t decide how I’m going to use it. :upside_down_face: