/** * Site Header Component * Sticky header container that holds top-bar, navigation, and search * Collapses on scroll down, expands on scroll up * Based on: https://stackoverflow.com/questions/63902512/ */ class SiteHeader extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.prevScrollPos = 0; this.headerOffset = 0; this.collapsibleHeight = 0; this.upwardScroll = 0; this.handleScroll = this.handleScroll.bind(this); } connectedCallback() { this.render(); this.collapsible = this.shadowRoot.querySelector(".collapsible"); window.addEventListener("scroll", this.handleScroll, { passive: true }); } disconnectedCallback() { window.removeEventListener("scroll", this.handleScroll); } handleScroll() { const currentScrollPos = Math.max(0, window.scrollY); const isScrollingDown = currentScrollPos > this.prevScrollPos; const delta = currentScrollPos - this.prevScrollPos; if (!this.collapsibleHeight && this.collapsible) { this.collapsibleHeight = this.collapsible.scrollHeight; } if (isScrollingDown) { this.upwardScroll = 0; this.headerOffset = Math.min( this.collapsibleHeight, Math.max(0, this.headerOffset + delta) ); this.classList.remove("reveal"); } else if (delta < 0) { this.upwardScroll += Math.abs(delta); if (this.upwardScroll >= 20) { this.headerOffset = 0; this.classList.add("reveal"); } } this.collapsible.style.transform = `translateY(-${this.headerOffset}px)`; this.prevScrollPos = currentScrollPos; } render() { this.shadowRoot.innerHTML = `
`; } } customElements.define("site-header", SiteHeader);