Alban's Blog

Changing Bear's Toast button to +1

I love how Bear blog feels like the old web. It's fast, text-first, and feels like plain HTML.

The only exception was the Toast icon at the bottom. I like having a way to say "I like this" but I wanted to restyle it to look more like an HTML link.

I landed on a +1 that looks like a link. When you click it, it thanks the reader and adds one to the counter. Then I added a script that adds "like" or "likes" to the counter depending if the blog has one or more likes.

Here's the CSS and script1 if you'd like to add it to your Bear blog.

This goes in Themes > Edit theme CSS

/* Minimal +1 upvote link for Bear */

form#upvote-form {
  display: block !important;
  margin: 2rem 0 1.5rem !important;
  padding: 0 !important;
  width: auto !important;

  font: inherit !important;
  font-size: 1em !important;
  line-height: inherit !important;
  color: inherit !important;

  white-space: nowrap !important;
  text-align: left !important;
}

/* Reset Bear's <small> wrappers so the upvote matches body text size */

form#upvote-form small {
  font: inherit !important;
  font-size: 1em !important;
  line-height: inherit !important;
}

/* Short, quiet rule above the +1 */

form#upvote-form::before {
  content: "";
  display: block;

  width: 3rem;
  margin: 0 0 1.25rem;

  border-top: 1px solid var(--rule-color, #ddd);
}

/* Reset Bear's native upvote button */

form#upvote-form button.upvote-button {
  appearance: none !important;
  -webkit-appearance: none !important;

  display: inline-flex !important;
  flex-direction: row !important;
  align-items: baseline !important;
  justify-content: flex-start !important;
  gap: 0.35ch !important;

  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;

  background: none !important;

  font: inherit !important;
  font-size: 1em !important;
  line-height: inherit !important;
  color: inherit !important;

  cursor: pointer;
  white-space: nowrap !important;
}

/* Hide Bear's default upvote icon */

form#upvote-form button.upvote-button svg,
form#upvote-form button.upvote-button .css-i6dzq1 {
  display: none !important;
}

/* Default clickable text */

form#upvote-form button.upvote-button::before {
  content: "+1";

  color: var(--link-color, #3273dc) !important;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Count */

form#upvote-form .upvote-count {
  display: inline !important;

  margin: 0 !important;
  padding: 0 !important;

  font: inherit !important;
  font-size: 1em !important;
  line-height: inherit !important;

  color: inherit !important;
  white-space: nowrap !important;
}

/* Separator before count */

form#upvote-form .upvote-count::before {
  content: "· ";
  color: inherit;
}

/* Optional label after count.
   If you are using the footer script for "1 like" / "2 likes",
   leave this as-is. */

form#upvote-form .upvote-count::after {
  content: attr(data-like-label);
  color: inherit;
}

/* Hover: still feels like a normal link */

form#upvote-form button.upvote-button:not([disabled]):not(.upvoted):hover::before {
  text-decoration-thickness: 2px;
}

/* Keyboard focus */

form#upvote-form button.upvote-button:focus-visible {
  outline: 1px solid var(--link-color, #3273dc);
  outline-offset: 3px;
}

/* Clicked / already-upvoted state */

form#upvote-form button.upvote-button[disabled],
form#upvote-form button.upvote-button.upvoted,
form#upvote-form.upvoted button.upvote-button {
  opacity: 1 !important;
  cursor: default !important;
  color: inherit !important;
}

/* After click */

form#upvote-form button.upvote-button[disabled]::before,
form#upvote-form button.upvote-button.upvoted::before,
form#upvote-form.upvoted button.upvote-button::before {
  content: "Thank you!";

  color: var(--link-color, #3273dc) !important;
  text-decoration: none;
}

This goes in Settings > Header and footer directives > Footer directive. If you don't want like/likes after the counter you can leave it out.

<script>
  (() => {
    const setupPlusOneLabel = () => {
      const count = document.querySelector("form#upvote-form .upvote-count");
      if (!count) return;

      const updateLabel = () => {
        const number = parseInt(count.textContent, 10);

        if (Number.isNaN(number)) {
          count.dataset.likeLabel = "";
          return;
        }

        count.dataset.likeLabel = number === 1 ? " like" : " likes";
      };

      updateLabel();

      new MutationObserver(updateLabel).observe(count, {
        childList: true,
        characterData: true,
        subtree: true
      });
    };

    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", setupPlusOneLabel);
    } else {
      setupPlusOneLabel();
    }
  })();
</script>
  1. I'm not a designer, so this was all written by iterating with ChatGPT. If there's a more elegant way to do this, I'd love to hear from you!