Reading Progress Bar in Bricks

This Pro tutorial provides the steps to implement a reading progress bar in Bricks builder.

Step 1

Add the progress element as the first child of body.

Go to Bricks → Settings → Custom code and paste the following in Body (header) scripts:

<progress aria-hidden="true" class="reset reading-progressbar js-reading-progressbar" max="100" value="0">
  <div class="reading-progressbar__fallback js-reading-progressbar__fallback"></div>
</progress>

While there, paste the following in Custom CSS text area (or, if you prefer – in child theme’s style.css):

/* -------------------------------- 

File#: _1_reading-progressbar
Title: Reading Progress Bar
Descr: A bar indicator displaying the current reading progress
Usage: codyhouse.co/license

-------------------------------- */

.reading-progressbar {
  position: fixed;
  z-index: 10;
  top: 0;
  left: 0;
  width: 100%;
  height: 5px;
  color: #4827ec;
  pointer-events: none;
  display: none;
  transition: -webkit-transform 0.2s;
  transition: transform 0.2s;
  transition: transform 0.2s, -webkit-transform 0.2s;
}

.admin-bar .reading-progressbar {
  top: var(--wp-admin--admin-bar--height,0);
}

.reading-progressbar--is-out {
  -webkit-transform: translateY(-100%);
          transform: translateY(-100%);
}

.reading-progressbar--is-active {
  display: block;
}

.reading-progressbar::-webkit-progress-bar {
  background-color: transparent;
}

.reading-progressbar::-webkit-progress-value {
  background-color: currentColor;
}

.reading-progressbar::-moz-progress-bar {
  background-color: currentColor;
}

.reading-progressbar__fallback {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  background-color: currentColor;
}

To change the color of the progress bar, change the color value in the above from #4827ec to your desired hex code.

Step 2

Create a directory called assets in your child theme directory and inside that, js directory.

Create a file named util.js inside the assets/js having:

// Utility function
function Util() {}

/* class manipulation functions */

Util.addClass = function (el, className) {
  var classList = className.split(" ");
  el.classList.add(classList[0]);
  if (classList.length > 1) Util.addClass(el, classList.slice(1).join(" "));
};

Util.removeClass = function (el, className) {
  var classList = className.split(" ");
  el.classList.remove(classList[0]);
  if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(" "));
};

Util.toggleClass = function (el, className, bool) {
  if (bool) Util.addClass(el, className);
  else Util.removeClass(el, className);
};

Create another file named reading-indicator.js in the same location having:

// File#: _1_reading-progressbar
// Usage: codyhouse.co/license
(function () {
  var readingIndicator = document.getElementsByClassName(
      "js-reading-progressbar"
    )[0],
    readingIndicatorContent = document.getElementById("brx-content");

  if (readingIndicator && readingIndicatorContent) {
    var progressInfo = [],
      progressEvent = false,
      progressFallback = readingIndicator.getElementsByClassName(
        "js-reading-progressbar__fallback"
      )[0],
      progressIsSupported = "value" in readingIndicator;

    var boundingClientRect = readingIndicatorContent.getBoundingClientRect();

    progressInfo["height"] = readingIndicatorContent.offsetHeight;
    progressInfo["top"] = boundingClientRect.top;
    progressInfo["bottom"] = boundingClientRect.bottom;
    progressInfo["window"] = window.innerHeight;
    progressInfo["class"] = "reading-progressbar--is-active";
    progressInfo["hideClass"] = "reading-progressbar--is-out";

    //init indicator
    setProgressIndicator();
    // wait for font to be loaded - reset progress bar
    if (document.fonts) {
      document.fonts.ready.then(function () {
        triggerReset();
      });
    }
    // listen to window resize - update progress
    window.addEventListener("resize", function (event) {
      triggerReset();
    });

    //listen to the window scroll event - update progress
    window.addEventListener("scroll", function (event) {
      if (progressEvent) return;
      progressEvent = true;
      !window.requestAnimationFrame
        ? setTimeout(function () {
            setProgressIndicator();
          }, 250)
        : window.requestAnimationFrame(setProgressIndicator);
    });

    function setProgressIndicator() {
      var boundingClientRect = readingIndicatorContent.getBoundingClientRect();
      progressInfo["top"] = boundingClientRect.top;
      progressInfo["bottom"] = boundingClientRect.bottom;

      if (progressInfo["height"] <= progressInfo["window"]) {
        // short content - hide progress indicator
        Util.removeClass(readingIndicator, progressInfo["class"]);
        progressEvent = false;
        return;
      }
      // get new progress and update element
      Util.addClass(readingIndicator, progressInfo["class"]);
      var value =
        progressInfo["top"] >= 0
          ? 0
          : (100 * (0 - progressInfo["top"])) /
            (progressInfo["height"] - progressInfo["window"]);
      readingIndicator.setAttribute("value", value);
      if (!progressIsSupported && progressFallback)
        progressFallback.style.width = value + "%";
      // hide progress bar when target is outside the viewport
      Util.toggleClass(
        readingIndicator,
        progressInfo["hideClass"],
        progressInfo["bottom"] <= 0
      );
      progressEvent = false;
    }

    function triggerReset() {
      if (progressEvent) return;
      progressEvent = true;
      !window.requestAnimationFrame
        ? setTimeout(function () {
            resetProgressIndicator();
          }, 250)
        : window.requestAnimationFrame(resetProgressIndicator);
    }

    function resetProgressIndicator() {
      progressInfo["height"] = readingIndicatorContent.offsetHeight;
      progressInfo["window"] = window.innerHeight;
      setProgressIndicator();
    }
  }
})();

Step 3

Edit child theme’s functions.php.

Inside the function hooked to wp_enqueue_scripts, add

wp_register_script( 'util', get_stylesheet_directory_uri() . '/assets/js/util.js', [], '1.0.0', true );
wp_enqueue_script( 'reading-indicator', get_stylesheet_directory_uri() . '/assets/js/reading-indicator.js', [ 'util' ], '1.0.0', true );

Source

https://codyhouse.co/ds/components/info/reading-progressbar