PageSourceSearch

https://startupkit.app/assets/controllers/csirt/pull_refresh_controller-40d2bf90.js

js startupkit.app collected 2026-10-06 04:55:48 UTC 2,173 bytes, 67 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3export default class extends Controller {
4  static targets = ["indicator"]
5  static values = { threshold: { type: Number, default: 80 } }
6
7  connect() {
8    this.startY = 0
9    this.pulling = false
10    // touchmove must be manually bound (not via data-action) because we need { passive: false }
11    // to allow preventDefault() which stops native scroll during the pull gesture
12    this.element.addEventListener("touchmove", this.boundTouchmove = this.handleTouchmove.bind(this), { passive: false })
13  }
14
15  disconnect() {
16    this.element.removeEventListener("touchmove", this.boundTouchmove)
17  }
18
19  touchstart(event) {
20    if (this.element.scrollTop <= 0) {
21      this.startY = event.touches[0].clientY
22      this.pulling = true
23    }
24  }
25
26  handleTouchmove(event) {
27    if (!this.pulling) return
28    const dy = event.touches[0].clientY - this.startY
29    if (dy < 0) { this.pulling = false; this.resetIndicator(); return }
30
31    const progress = Math.min(dy / this.thresholdValue, 1)
32    const dampedDy = dy * 0.4
33    this.indicatorTarget.style.transform = `translateY(${dampedDy}px)`
34    this.indicatorTarget.style.opacity = progress
35    this.indicatorTarget.classList.toggle("text-indigo-500", progress >= 1)
36    this.indicatorTarget.classList.toggle("text-gray-400", progress < 1)
37
38    if (dy > 10) event.preventDefault()
39  }
40
41  touchend() {
42    if (!this.pulling) return
43    const wasReady = parseFloat(this.indicatorTarget.style.opacity) >= 1
44    this.pulling = false
45
46    if (wasReady) {
47      this.reload()
48    }
49    this.resetIndicator()
50  }
51
52  reload() {
53    if (navigator.vibrate) navigator.vibrate(10)
54    this.element.querySelectorAll("turbo-frame[src]").forEach((frame) => {
55      const src = frame.getAttribute("src")
56      frame.removeAttribute("src")
57      requestAnimationFrame(() => frame.setAttribute("src", src))
58    })
59  }
60
61  resetIndicator() {
62    this.indicatorTarget.style.transition = "transform 200ms ease, opacity 200ms ease"
63    this.indicatorTarget.style.transform = ""
64    this.indicatorTarget.style.opacity = "0"
65    setTimeout(() => { this.indicatorTarget.style.transition = "" }, 200)
66  }
67}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.