import { Controller } from "@hotwired/stimulus" // Over dark heroes: transparent at page top → solid hero blue while scrolling in hero → white past hero. // Uses inline styles (always wins over CSS) to avoid Tailwind cascade battles. // Dropdown panels stay white (standard pattern: Stripe, Linear, Vercel). /** Pixels scrolled before the bar picks up the solid hero background (#0A0F1E). */ const TRANSPARENT_TOP_PX = 48 export default class extends Controller { static targets = ["darkLogo", "whiteLogo", "navLink", "loginLink", "ctaButton", "mobileButton", "divider", "container"] connect() { this._onScroll = this._onScroll.bind(this) this._lastPhase = null // The hero element is below the navbar in the DOM, so it may not exist yet // when this controller connects. Wait for the full DOM to be ready. if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => this._init(), { once: true }) } else { // Suppress transition NOW (synchronous, before browser paints) so there is no white flash. // The RAF below lets layout complete so getBoundingClientRect() is accurate. this.element.style.transition = "none" requestAnimationFrame(() => this._init()) } } _init() { this._heroEl = document.querySelector("[data-dark-hero]") if (!this._heroEl) { this.element.style.transition = "" return } this._dropdownButtons = this.element.querySelectorAll("[data-controller='nav-dropdown'] > div > button") this._ticking = false window.addEventListener("scroll", this._onScroll, { passive: true }) this._updateFromScroll() // Re-enable transitions after initial state is applied (transition was suppressed in connect()) requestAnimationFrame(() => { this.element.style.transition = "" }) } disconnect() { window.removeEventListener("scroll", this._onScroll) } _onScroll() { if (this._ticking) return this._ticking = true requestAnimationFrame(() => { this._ticking = false this._updateFromScroll() }) } _updateFromScroll() { if (!this._heroEl) return const scrollY = window.scrollY || document.documentElement.scrollTop const heroBottom = this._heroEl.getBoundingClientRect().bottom const pastHero = heroBottom <= 0 let phase if (pastHero) { phase = "light" } else if (scrollY < TRANSPARENT_TOP_PX) { phase = "transparent" } else { phase = "dark" } if (phase === this._lastPhase) return this._lastPhase = phase this._applyPhase(phase) } _applyPhase(phase) { const el = this.element if (phase === "light") { el.style.backgroundColor = "" el.style.borderBottomColor = "" if (this.hasDarkLogoTarget) this.darkLogoTarget.style.display = "" if (this.hasWhiteLogoTarget) this.whiteLogoTarget.style.display = "none" this.navLinkTargets.forEach(link => { link.style.color = "" }) if (this.hasLoginLinkTarget) this.loginLinkTarget.style.color = "" if (this.hasCtaButtonTarget) { this.ctaButtonTarget.style.backgroundColor = "" this.ctaButtonTarget.style.color = "" this.ctaButtonTarget.style.border = "" } this.mobileButtonTargets.forEach(btn => { btn.style.color = "" }) this.dividerTargets.forEach(hr => { hr.style.borderColor = "" }) if (this.hasContainerTarget) this.containerTarget.style.borderColor = "" this._dropdownButtons.forEach(btn => { btn.style.color = "" }) return } // transparent or dark: light-on-dark chrome; only background differs el.style.backgroundColor = phase === "dark" ? "#0A0F1E" : "transparent" el.style.borderBottomColor = "transparent" if (this.hasDarkLogoTarget) this.darkLogoTarget.style.display = "none" if (this.hasWhiteLogoTarget) this.whiteLogoTarget.style.display = "inline" this.navLinkTargets.forEach(link => { link.style.color = "rgba(255, 255, 255, 0.85)" }) if (this.hasLoginLinkTarget) { this.loginLinkTarget.style.color = "rgba(255, 255, 255, 0.85)" } if (this.hasCtaButtonTarget) { this.ctaButtonTarget.style.backgroundColor = "rgba(255, 255, 255, 0.12)" this.ctaButtonTarget.style.color = "rgba(255, 255, 255, 0.95)" this.ctaButtonTarget.style.border = "1px solid rgba(255, 255, 255, 0.2)" } this.mobileButtonTargets.forEach(btn => { btn.style.color = "rgba(255, 255, 255, 0.85)" }) this.dividerTargets.forEach(hr => { hr.style.borderColor = "transparent" }) if (this.hasContainerTarget) { this.containerTarget.style.borderColor = "transparent" } this._dropdownButtons.forEach(btn => { btn.style.color = "rgba(255, 255, 255, 0.85)" }) } }