Files
fizzy/app/javascript/controllers/bridge/page_controller.js
T
2026-01-08 16:22:55 +01:00

90 lines
2.0 KiB
JavaScript

import { BridgeComponent } from "@hotwired/hotwire-native-bridge"
import { viewport } from "helpers/bridge/viewport_helpers"
import { nextFrame } from "helpers/timing_helpers"
export default class extends BridgeComponent {
static component = "page"
static targets = [ "header" ]
static values = { title: String }
async connect() {
super.connect()
this.notifyBridgeOfPageChange()
await nextFrame()
this.startObserver()
window.addEventListener("resize", this.windowResized)
}
disconnect() {
super.disconnect()
this.stopObserver()
window.removeEventListener("resize", this.windowResized)
}
receive(message) {
switch (message.event) {
case "set-text-size":
this.setTextSize(message.data)
break
}
}
setTextSize(data) {
document.documentElement.dataset.textSize = data.textSize
}
// Bridge
notifyBridgeOfPageChange() {
const data = { title: this.title }
if (this.hasHeaderTarget) {
// Assume header visible by default until we get IntersectionObserver update
data.elementVisible = true
}
this.send("change", data, message => this.receive(message))
}
notifyBridgeOfVisibilityChange(visible) {
this.send("visibility", { title: this.title, elementVisible: visible })
}
// Intersection Observer
startObserver() {
if (!this.hasHeaderTarget) return
this.observer = new IntersectionObserver(([ entry ]) =>
this.notifyBridgeOfVisibilityChange(entry.isIntersecting),
{ rootMargin: `-${this.topOffset}px 0px 0px 0px` }
)
this.observer.observe(this.headerTarget)
this.previousTopOffset = this.topOffset
}
stopObserver() {
this.observer?.disconnect()
}
updateObserverIfNeeded() {
if (this.topOffset === this.previousTopOffset) return
this.stopObserver()
this.startObserver()
}
windowResized = () => {
this.updateObserverIfNeeded()
}
get title() {
return this.titleValue ? this.titleValue : document.title
}
get topOffset() {
return viewport.top
}
}