chunk-009-toc.js

I’ll build this as a strong Table of Contents chunk for chunk-009-toc.js: auto-generating TOC from headings, smooth scroll, active heading highlight, collapsible/mobile behavior, accessibility, copy-link support, progress reading bar hooks, and WordPress-friendly safety checks.

Dear friend, create this file:

assets/static-js/static-chunks-js/chunk-009-toc.js

Then paste this full advanced code inside it.

/*!
 * RX Theme - Advanced Table of Contents Chunk
 * File: assets/static-js/static-chunks-js/chunk-009-toc.js
 * Author: RX Theme
 * Purpose:
 * - Auto-generate table of contents from post headings
 * - Smooth scroll to headings
 * - Active heading highlight while scrolling
 * - Mobile collapse/expand
 * - Copy heading link
 * - Reading progress support
 * - Accessibility-friendly navigation
 * - WordPress-safe, no dependency required
 */

(function () {
  'use strict';

  /**
   * ==========================================================
   * RX TOC CONFIG
   * ==========================================================
   */

  var RX_TOC_CONFIG = {
    contentSelector: [
      '.entry-content',
      '.post-content',
      '.single-post-content',
      '.rx-post-content',
      'article .content',
      'article'
    ],

    tocMountSelector: [
      '[data-rx-toc]',
      '#rx-toc',
      '.rx-toc'
    ],

    headingSelector: 'h2, h3, h4',

    excludeHeadingSelector: [
      '.no-toc',
      '.rx-no-toc',
      '[data-no-toc]',
      '.screen-reader-text',
      '.wp-block-heading.no-toc'
    ].join(','),

    minHeadings: 2,

    maxTitleLength: 120,

    scrollOffset: 90,

    activeOffset: 120,

    smoothScroll: true,

    updateHash: true,

    copyLink: true,

    addHeadingAnchors: true,

    collapsible: true,

    startCollapsedOnMobile: true,

    mobileBreakpoint: 768,

    readingProgress: true,

    debug: false
  };

  /**
   * ==========================================================
   * SMALL HELPERS
   * ==========================================================
   */

  function rxLog() {
    if (!RX_TOC_CONFIG.debug) return;
    if (window.console && typeof window.console.log === 'function') {
      window.console.log.apply(window.console, arguments);
    }
  }

  function qs(selector, root) {
    return (root || document).querySelector(selector);
  }

  function qsa(selector, root) {
    return Array.prototype.slice.call((root || document).querySelectorAll(selector));
  }

  function isElement(node) {
    return node && node.nodeType === 1;
  }

  function isVisible(el) {
    if (!isElement(el)) return false;
    var style = window.getComputedStyle(el);
    return (
      style.display !== 'none' &&
      style.visibility !== 'hidden' &&
      style.opacity !== '0' &&
      el.offsetParent !== null
    );
  }

  function getFirstExistingSelector(selectors) {
    for (var i = 0; i < selectors.length; i++) {
      var el = qs(selectors[i]);
      if (el) return el;
    }
    return null;
  }

  function cleanText(text) {
    return String(text || '')
      .replace(/\s+/g, ' ')
      .replace(/^\s+|\s+$/g, '');
  }

  function truncateText(text, max) {
    text = cleanText(text);
    if (text.length <= max) return text;
    return text.substring(0, max).replace(/\s+\S*$/, '') + '…';
  }

  function slugify(text) {
    return cleanText(text)
      .toLowerCase()
      .replace(/&/g, ' and ')
      .replace(/[^\w\u0980-\u09FF\u0900-\u097F\u0600-\u06FF\s-]/g, '')
      .replace(/\s+/g, '-')
      .replace(/-+/g, '-')
      .replace(/^-|-$/g, '');
  }

  function uniqueId(base, usedIds) {
    var id = base || 'rx-heading';
    var finalId = id;
    var count = 2;

    while (usedIds[finalId] || document.getElementById(finalId)) {
      finalId = id + '-' + count;
      count++;
    }

    usedIds[finalId] = true;
    return finalId;
  }

  function getHeadingLevel(heading) {
    return parseInt(heading.tagName.replace('H', ''), 10);
  }

  function createEl(tag, className, attrs) {
    var el = document.createElement(tag);

    if (className) {
      el.className = className;
    }

    if (attrs) {
      Object.keys(attrs).forEach(function (key) {
        if (attrs[key] !== null && attrs[key] !== undefined) {
          el.setAttribute(key, attrs[key]);
        }
      });
    }

    return el;
  }

  function getScrollTop() {
    return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  }

  function getDocumentHeight() {
    var body = document.body;
    var html = document.documentElement;

    return Math.max(
      body.scrollHeight,
      body.offsetHeight,
      html.clientHeight,
      html.scrollHeight,
      html.offsetHeight
    );
  }

  function prefersReducedMotion() {
    return window.matchMedia &&
      window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  }

  function debounce(fn, wait) {
    var timeout;

    return function () {
      var context = this;
      var args = arguments;

      clearTimeout(timeout);

      timeout = setTimeout(function () {
        fn.apply(context, args);
      }, wait);
    };
  }

  function throttle(fn, limit) {
    var inThrottle = false;

    return function () {
      var context = this;
      var args = arguments;

      if (!inThrottle) {
        fn.apply(context, args);
        inThrottle = true;

        setTimeout(function () {
          inThrottle = false;
        }, limit);
      }
    };
  }

  /**
   * ==========================================================
   * MAIN RX TOC CLASS
   * ==========================================================
   */

  function RxAdvancedTOC() {
    this.content = null;
    this.mount = null;
    this.headings = [];
    this.links = [];
    this.usedIds = {};
    this.activeId = null;
    this.observer = null;
    this.progressBar = null;
    this.isCollapsed = false;
  }

  RxAdvancedTOC.prototype.init = function () {
    this.content = getFirstExistingSelector(RX_TOC_CONFIG.contentSelector);
    this.mount = getFirstExistingSelector(RX_TOC_CONFIG.tocMountSelector);

    if (!this.content) {
      rxLog('[RX TOC] No content area found.');
      return;
    }

    this.headings = this.collectHeadings();

    if (this.headings.length < RX_TOC_CONFIG.minHeadings) {
      rxLog('[RX TOC] Not enough headings.');
      this.hideMountIfExists();
      return;
    }

    this.prepareHeadingIds();

    if (!this.mount) {
      this.mount = this.createDefaultMount();
    }

    this.renderTOC();
    this.bindEvents();
    this.setupActiveObserver();
    this.setupReadingProgress();
    this.handleInitialHash();
    this.setInitialMobileState();

    document.documentElement.classList.add('rx-toc-ready');

    rxLog('[RX TOC] Initialized.');
  };

  /**
   * ==========================================================
   * COLLECT HEADINGS
   * ==========================================================
   */

  RxAdvancedTOC.prototype.collectHeadings = function () {
    var headings = qsa(RX_TOC_CONFIG.headingSelector, this.content);

    headings = headings.filter(function (heading) {
      if (!heading || !heading.textContent) return false;
      if (heading.matches(RX_TOC_CONFIG.excludeHeadingSelector)) return false;
      if (heading.closest(RX_TOC_CONFIG.excludeHeadingSelector)) return false;
      if (!isVisible(heading)) return false;

      var text = cleanText(heading.textContent);

      if (!text) return false;
      if (heading.closest('.rx-toc')) return false;
      if (heading.closest('[data-rx-toc]')) return false;

      return true;
    });

    return headings;
  };

  /**
   * ==========================================================
   * PREPARE IDS
   * ==========================================================
   */

  RxAdvancedTOC.prototype.prepareHeadingIds = function () {
    var self = this;

    this.headings.forEach(function (heading) {
      var existingId = heading.getAttribute('id');
      var baseId = existingId || slugify(heading.textContent);

      if (!baseId) {
        baseId = 'rx-heading';
      }

      var finalId = existingId || uniqueId(baseId, self.usedIds);

      heading.setAttribute('id', finalId);
      heading.setAttribute('tabindex', '-1');
      heading.classList.add('rx-toc-heading');

      if (RX_TOC_CONFIG.addHeadingAnchors) {
        self.addAnchorToHeading(heading, finalId);
      }
    });
  };

  /**
   * ==========================================================
   * ADD HEADING ANCHOR BUTTON
   * ==========================================================
   */

  RxAdvancedTOC.prototype.addAnchorToHeading = function (heading, id) {
    if (heading.querySelector('.rx-heading-anchor')) return;

    var anchor = createEl('a', 'rx-heading-anchor', {
      href: '#' + id,
      'aria-label': 'Copy link to this section',
      title: 'Copy link to this section'
    });

    anchor.innerHTML = '<span aria-hidden="true">#</span>';

    anchor.addEventListener('click', function (event) {
      if (!RX_TOC_CONFIG.copyLink) return;

      event.preventDefault();

      var url = window.location.origin + window.location.pathname + '#' + id;

      copyText(url, function () {
        anchor.classList.add('is-copied');
        anchor.setAttribute('title', 'Copied!');

        setTimeout(function () {
          anchor.classList.remove('is-copied');
          anchor.setAttribute('title', 'Copy link to this section');
        }, 1200);
      });
    });

    heading.appendChild(anchor);
  };

  /**
   * ==========================================================
   * CREATE DEFAULT MOUNT
   * ==========================================================
   */

  RxAdvancedTOC.prototype.createDefaultMount = function () {
    var mount = createEl('aside', 'rx-toc rx-toc-auto', {
      id: 'rx-toc',
      'data-rx-toc': 'auto',
      'aria-label': 'Table of contents'
    });

    if (this.content.parentNode) {
      this.content.parentNode.insertBefore(mount, this.content);
    }

    return mount;
  };

  RxAdvancedTOC.prototype.hideMountIfExists = function () {
    var mount = getFirstExistingSelector(RX_TOC_CONFIG.tocMountSelector);
    if (mount) {
      mount.hidden = true;
      mount.classList.add('rx-toc-hidden');
    }
  };

  /**
   * ==========================================================
   * RENDER TOC
   * ==========================================================
   */

  RxAdvancedTOC.prototype.renderTOC = function () {
    var self = this;

    this.mount.innerHTML = '';
    this.mount.classList.add('rx-toc');
    this.mount.setAttribute('role', 'navigation');
    this.mount.setAttribute('aria-label', 'Table of contents');

    var header = createEl('div', 'rx-toc-header');

    var title = createEl('div', 'rx-toc-title', {
      id: 'rx-toc-title'
    });

    title.textContent = 'Contents';

    var toggle = createEl('button', 'rx-toc-toggle', {
      type: 'button',
      'aria-expanded': 'true',
      'aria-controls': 'rx-toc-list-wrap'
    });

    toggle.innerHTML =
      '<span class="rx-toc-toggle-text">Show/Hide</span>' +
      '<span class="rx-toc-toggle-icon" aria-hidden="true">⌄</span>';

    header.appendChild(title);

    if (RX_TOC_CONFIG.collapsible) {
      header.appendChild(toggle);
    }

    var listWrap = createEl('div', 'rx-toc-list-wrap', {
      id: 'rx-toc-list-wrap'
    });

    var list = createEl('ol', 'rx-toc-list');

    this.headings.forEach(function (heading, index) {
      var id = heading.getAttribute('id');
      var level = getHeadingLevel(heading);
      var text = truncateText(heading.textContent, RX_TOC_CONFIG.maxTitleLength);

      var item = createEl('li', 'rx-toc-item rx-toc-level-' + level, {
        'data-heading-id': id,
        'data-heading-level': level
      });

      var link = createEl('a', 'rx-toc-link', {
        href: '#' + id,
        'data-rx-toc-link': id
      });

      link.innerHTML =
        '<span class="rx-toc-number">' + (index + 1) + '</span>' +
        '<span class="rx-toc-text">' + escapeHTML(text) + '</span>';

      item.appendChild(link);
      list.appendChild(item);

      self.links.push(link);
    });

    listWrap.appendChild(list);

    var footer = createEl('div', 'rx-toc-footer');
    footer.innerHTML =
      '<button type="button" class="rx-toc-top-button" data-rx-scroll-top>' +
      'Back to top' +
      '</button>';

    this.mount.appendChild(header);
    this.mount.appendChild(listWrap);
    this.mount.appendChild(footer);

    this.toggleButton = toggle;
    this.listWrap = listWrap;
  };

  /**
   * ==========================================================
   * BIND EVENTS
   * ==========================================================
   */

  RxAdvancedTOC.prototype.bindEvents = function () {
    var self = this;

    this.links.forEach(function (link) {
      link.addEventListener('click', function (event) {
        var id = link.getAttribute('data-rx-toc-link');
        var target = document.getElementById(id);

        if (!target) return;

        event.preventDefault();

        self.scrollToHeading(target);

        if (RX_TOC_CONFIG.updateHash) {
          self.updateUrlHash(id);
        }

        self.setActive(id, true);
      });
    });

    if (this.toggleButton) {
      this.toggleButton.addEventListener('click', function () {
        self.toggleCollapse();
      });
    }

    var topButton = qs('[data-rx-scroll-top]', this.mount);

    if (topButton) {
      topButton.addEventListener('click', function () {
        self.scrollToTop();
      });
    }

    window.addEventListener(
      'resize',
      debounce(function () {
        self.setInitialMobileState();
      }, 200),
      { passive: true }
    );

    window.addEventListener(
      'scroll',
      throttle(function () {
        self.updateActiveByScroll();
        self.updateReadingProgress();
      }, 80),
      { passive: true }
    );

    document.addEventListener('keydown', function (event) {
      self.handleKeyboard(event);
    });
  };

  /**
   * ==========================================================
   * SMOOTH SCROLL
   * ==========================================================
   */

  RxAdvancedTOC.prototype.scrollToHeading = function (target) {
    var offset = RX_TOC_CONFIG.scrollOffset;
    var top = target.getBoundingClientRect().top + getScrollTop() - offset;

    if (RX_TOC_CONFIG.smoothScroll && !prefersReducedMotion()) {
      window.scrollTo({
        top: top,
        behavior: 'smooth'
      });
    } else {
      window.scrollTo(0, top);
    }

    setTimeout(function () {
      try {
        target.focus({ preventScroll: true });
      } catch (e) {
        target.focus();
      }
    }, 350);
  };

  RxAdvancedTOC.prototype.scrollToTop = function () {
    if (RX_TOC_CONFIG.smoothScroll && !prefersReducedMotion()) {
      window.scrollTo({
        top: 0,
        behavior: 'smooth'
      });
    } else {
      window.scrollTo(0, 0);
    }
  };

  RxAdvancedTOC.prototype.updateUrlHash = function (id) {
    if (!history || !history.pushState) return;

    try {
      history.pushState(null, '', '#' + encodeURIComponent(id));
    } catch (e) {
      window.location.hash = id;
    }
  };

  /**
   * ==========================================================
   * ACTIVE LINK OBSERVER
   * ==========================================================
   */

  RxAdvancedTOC.prototype.setupActiveObserver = function () {
    var self = this;

    if (!('IntersectionObserver' in window)) {
      this.updateActiveByScroll();
      return;
    }

    var options = {
      root: null,
      rootMargin: '-20% 0px -65% 0px',
      threshold: [0, 1]
    };

    this.observer = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          self.setActive(entry.target.getAttribute('id'), false);
        }
      });
    }, options);

    this.headings.forEach(function (heading) {
      self.observer.observe(heading);
    });
  };

  RxAdvancedTOC.prototype.updateActiveByScroll = function () {
    var scrollPosition = getScrollTop() + RX_TOC_CONFIG.activeOffset;
    var current = null;

    for (var i = 0; i < this.headings.length; i++) {
      var heading = this.headings[i];
      var top = heading.getBoundingClientRect().top + getScrollTop();

      if (top <= scrollPosition) {
        current = heading;
      } else {
        break;
      }
    }

    if (current) {
      this.setActive(current.getAttribute('id'), false);
    }
  };

  RxAdvancedTOC.prototype.setActive = function (id, fromClick) {
    if (!id || this.activeId === id) return;

    this.activeId = id;

    this.links.forEach(function (link) {
      var isActive = link.getAttribute('data-rx-toc-link') === id;
      var item = link.closest('.rx-toc-item');

      link.classList.toggle('is-active', isActive);
      link.setAttribute('aria-current', isActive ? 'true' : 'false');

      if (item) {
        item.classList.toggle('is-active', isActive);
      }
    });

    var activeLink = qs('[data-rx-toc-link="' + cssEscape(id) + '"]', this.mount);

    if (activeLink && !fromClick) {
      this.scrollActiveLinkIntoView(activeLink);
    }
  };

  RxAdvancedTOC.prototype.scrollActiveLinkIntoView = function (link) {
    if (!this.listWrap) return;

    var wrapRect = this.listWrap.getBoundingClientRect();
    var linkRect = link.getBoundingClientRect();

    if (linkRect.top < wrapRect.top || linkRect.bottom > wrapRect.bottom) {
      try {
        link.scrollIntoView({
          block: 'nearest',
          inline: 'nearest'
        });
      } catch (e) {
        link.scrollIntoView();
      }
    }
  };

  /**
   * ==========================================================
   * COLLAPSE / EXPAND
   * ==========================================================
   */

  RxAdvancedTOC.prototype.toggleCollapse = function () {
    this.setCollapsed(!this.isCollapsed);
  };

  RxAdvancedTOC.prototype.setCollapsed = function (state) {
    this.isCollapsed = !!state;

    this.mount.classList.toggle('is-collapsed', this.isCollapsed);

    if (this.listWrap) {
      this.listWrap.hidden = this.isCollapsed;
    }

    if (this.toggleButton) {
      this.toggleButton.setAttribute('aria-expanded', this.isCollapsed ? 'false' : 'true');
    }
  };

  RxAdvancedTOC.prototype.setInitialMobileState = function () {
    if (!RX_TOC_CONFIG.collapsible || !RX_TOC_CONFIG.startCollapsedOnMobile) return;

    var isMobile = window.innerWidth <= RX_TOC_CONFIG.mobileBreakpoint;

    if (isMobile) {
      this.setCollapsed(true);
    } else {
      this.setCollapsed(false);
    }
  };

  /**
   * ==========================================================
   * INITIAL HASH SUPPORT
   * ==========================================================
   */

  RxAdvancedTOC.prototype.handleInitialHash = function () {
    var hash = window.location.hash;

    if (!hash) {
      this.updateActiveByScroll();
      return;
    }

    var id = decodeURIComponent(hash.replace('#', ''));
    var target = document.getElementById(id);

    if (!target) {
      this.updateActiveByScroll();
      return;
    }

    var self = this;

    setTimeout(function () {
      self.scrollToHeading(target);
      self.setActive(id, true);
    }, 250);
  };

  /**
   * ==========================================================
   * READING PROGRESS
   * ==========================================================
   */

  RxAdvancedTOC.prototype.setupReadingProgress = function () {
    if (!RX_TOC_CONFIG.readingProgress) return;

    var existing = qs('.rx-reading-progress-bar');

    if (existing) {
      this.progressBar = existing;
      this.updateReadingProgress();
      return;
    }

    var progressWrap = createEl('div', 'rx-reading-progress', {
      'aria-hidden': 'true'
    });

    var progressBar = createEl('div', 'rx-reading-progress-bar');

    progressWrap.appendChild(progressBar);
    document.body.appendChild(progressWrap);

    this.progressBar = progressBar;
    this.updateReadingProgress();
  };

  RxAdvancedTOC.prototype.updateReadingProgress = function () {
    if (!this.progressBar) return;

    var scrollTop = getScrollTop();
    var docHeight = getDocumentHeight() - window.innerHeight;

    if (docHeight <= 0) {
      this.progressBar.style.width = '0%';
      return;
    }

    var percent = Math.min(100, Math.max(0, (scrollTop / docHeight) * 100));
    this.progressBar.style.width = percent.toFixed(2) + '%';
  };

  /**
   * ==========================================================
   * KEYBOARD SUPPORT
   * ==========================================================
   */

  RxAdvancedTOC.prototype.handleKeyboard = function (event) {
    if (!this.mount || !this.mount.contains(document.activeElement)) return;

    var currentIndex = this.links.indexOf(document.activeElement);

    if (currentIndex === -1) return;

    var nextIndex = currentIndex;

    if (event.key === 'ArrowDown') {
      nextIndex = Math.min(this.links.length - 1, currentIndex + 1);
    } else if (event.key === 'ArrowUp') {
      nextIndex = Math.max(0, currentIndex - 1);
    } else if (event.key === 'Home') {
      nextIndex = 0;
    } else if (event.key === 'End') {
      nextIndex = this.links.length - 1;
    } else {
      return;
    }

    event.preventDefault();

    if (this.links[nextIndex]) {
      this.links[nextIndex].focus();
    }
  };

  /**
   * ==========================================================
   * COPY TEXT HELPER
   * ==========================================================
   */

  function copyText(text, callback) {
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).then(function () {
        if (typeof callback === 'function') callback();
      }).catch(function () {
        fallbackCopy(text, callback);
      });

      return;
    }

    fallbackCopy(text, callback);
  }

  function fallbackCopy(text, callback) {
    var textarea = document.createElement('textarea');

    textarea.value = text;
    textarea.setAttribute('readonly', '');
    textarea.style.position = 'fixed';
    textarea.style.top = '-9999px';
    textarea.style.left = '-9999px';

    document.body.appendChild(textarea);
    textarea.select();

    try {
      document.execCommand('copy');
      if (typeof callback === 'function') callback();
    } catch (e) {
      rxLog('[RX TOC] Copy failed.', e);
    }

    document.body.removeChild(textarea);
  }

  /**
   * ==========================================================
   * SAFE HTML ESCAPE
   * ==========================================================
   */

  function escapeHTML(value) {
    return String(value || '')
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;');
  }

  /**
   * ==========================================================
   * CSS ESCAPE FALLBACK
   * ==========================================================
   */

  function cssEscape(value) {
    if (window.CSS && typeof window.CSS.escape === 'function') {
      return window.CSS.escape(value);
    }

    return String(value).replace(/["\\#.;?+*~':"!^$[\]()=>|/@]/g, '\\$&');
  }

  /**
   * ==========================================================
   * PUBLIC API
   * ==========================================================
   */

  window.RxAdvancedTOC = {
    instance: null,

    init: function () {
      if (this.instance) return this.instance;

      this.instance = new RxAdvancedTOC();
      this.instance.init();

      return this.instance;
    },

    refresh: function () {
      if (this.instance && this.instance.observer) {
        this.instance.observer.disconnect();
      }

      this.instance = new RxAdvancedTOC();
      this.instance.init();

      return this.instance;
    },

    config: RX_TOC_CONFIG
  };

  /**
   * ==========================================================
   * AUTO INIT
   * ==========================================================
   */

  function boot() {
    window.RxAdvancedTOC.init();
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
  } else {
    boot();
  }

})();

Add this HTML where you want the TOC to appear inside your single post template:

<aside id="rx-toc" class="rx-toc" data-rx-toc></aside>

Best place:

<?php if ( is_single() ) : ?>
    <aside id="rx-toc" class="rx-toc" data-rx-toc></aside>
<?php endif; ?>

Add this CSS later in your TOC CSS file:

.rx-toc {
  border: 1px solid var(--rx-border-color, #e5e7eb);
  border-radius: 12px;
  padding: 16px;
  background: var(--rx-surface-color, #ffffff);
  margin-bottom: 24px;
}

.rx-toc-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.rx-toc-title {
  font-weight: 700;
  font-size: 18px;
}

.rx-toc-toggle {
  cursor: pointer;
  border: 0;
  background: transparent;
  font: inherit;
}

.rx-toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rx-toc-item {
  margin: 4px 0;
}

.rx-toc-level-3 {
  padding-left: 16px;
}

.rx-toc-level-4 {
  padding-left: 32px;
}

.rx-toc-link {
  display: flex;
  gap: 8px;
  text-decoration: none;
  padding: 6px 8px;
  border-radius: 8px;
  color: inherit;
}

.rx-toc-link:hover,
.rx-toc-link.is-active {
  background: var(--rx-muted-color, #f3f4f6);
}

.rx-toc-number {
  opacity: 0.65;
  min-width: 24px;
}

.rx-heading-anchor {
  margin-left: 8px;
  text-decoration: none;
  opacity: 0;
  font-size: 0.8em;
}

.rx-toc-heading:hover .rx-heading-anchor {
  opacity: 0.7;
}

.rx-heading-anchor.is-copied {
  opacity: 1;
}

.rx-reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  z-index: 99999;
  pointer-events: none;
}

.rx-reading-progress-bar {
  width: 0%;
  height: 100%;
  background: var(--rx-primary-color, #2563eb);
}

.rx-toc-footer {
  margin-top: 12px;
}

.rx-toc-top-button {
  cursor: pointer;
  border: 0;
  background: transparent;
  padding: 6px 0;
  font: inherit;
  color: var(--rx-primary-color, #2563eb);
}

Enqueue it in your theme:

wp_enqueue_script(
    'rx-chunk-009-toc',
    get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-009-toc.js',
    array(),
    wp_get_theme()->get( 'Version' ),
    true
);

This file is safe for your RX Theme because it does not depend on jQuery, does not break pages without TOC, and only activates when headings are found inside the article content.

Leave a Reply

Your email address will not be published. Required fields are marked *