chore: Counter now embedded with Stimulus
Before this commit, Counter js was autonomous. Now it's registered like a controller in Stimulus.
This commit is contained in:
@@ -1,16 +1,3 @@
|
||||
// Entry point for the build script in your package.json
|
||||
import "@hotwired/turbo-rails"
|
||||
import "./controllers"
|
||||
import Counter from "./components/counter"
|
||||
|
||||
// Initialize counters when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const counters = document.querySelectorAll('.counter')
|
||||
counters.forEach(counter => new Counter(counter))
|
||||
})
|
||||
|
||||
// Re-initialize counters on Turbo page loads
|
||||
document.addEventListener('turbo:load', () => {
|
||||
const counters = document.querySelectorAll('.counter')
|
||||
counters.forEach(counter => new Counter(counter))
|
||||
})
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
export default class Counter {
|
||||
constructor(element) {
|
||||
this.element = element
|
||||
this.target = parseFloat(element.dataset.target)
|
||||
this.decimal = element.dataset.decimal === 'true'
|
||||
this.duration = 2000
|
||||
this.startTime = null
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
init() {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
this.animate()
|
||||
observer.unobserve(this.element)
|
||||
}
|
||||
})
|
||||
}, { threshold: 0.5 })
|
||||
|
||||
observer.observe(this.element)
|
||||
}
|
||||
|
||||
animate() {
|
||||
const startValue = 0
|
||||
const startTime = performance.now()
|
||||
|
||||
const updateCounter = (currentTime) => {
|
||||
const elapsedTime = currentTime - startTime
|
||||
const progress = Math.min(elapsedTime / this.duration, 1)
|
||||
|
||||
// Easing function for smooth animation
|
||||
const easeOutQuart = 1 - Math.pow(1 - progress, 4)
|
||||
|
||||
let currentValue = startValue + (this.target - startValue) * easeOutQuart
|
||||
|
||||
if (this.decimal && this.target < 10) {
|
||||
currentValue = currentValue.toFixed(1)
|
||||
} else {
|
||||
currentValue = Math.floor(currentValue)
|
||||
}
|
||||
|
||||
this.element.textContent = currentValue
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(updateCounter)
|
||||
} else {
|
||||
this.element.textContent = this.decimal && this.target < 10 ? this.target.toFixed(1) : this.target
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(updateCounter)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize all counters
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const counters = document.querySelectorAll('.counter')
|
||||
counters.forEach(counter => new Counter(counter))
|
||||
})
|
||||
@@ -1,2 +1,61 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static values = {
|
||||
target: Number,
|
||||
decimal: Boolean,
|
||||
duration: { type: Number, default: 2000 }
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
this.animate()
|
||||
this.observer.unobserve(this.element)
|
||||
}
|
||||
})
|
||||
}, { threshold: 0.5 })
|
||||
|
||||
this.observer.observe(this.element)
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.observer) {
|
||||
this.observer.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
animate() {
|
||||
const startValue = 0
|
||||
const startTime = performance.now()
|
||||
|
||||
const updateCounter = (currentTime) => {
|
||||
const elapsedTime = currentTime - startTime
|
||||
const progress = Math.min(elapsedTime / this.durationValue, 1)
|
||||
|
||||
// Easing function for smooth animation
|
||||
const easeOutQuart = 1 - Math.pow(1 - progress, 4)
|
||||
|
||||
let currentValue = startValue + (this.targetValue - startValue) * easeOutQuart
|
||||
|
||||
if (this.decimalValue && this.targetValue < 10) {
|
||||
currentValue = currentValue.toFixed(1)
|
||||
} else {
|
||||
currentValue = Math.floor(currentValue)
|
||||
}
|
||||
|
||||
this.element.textContent = currentValue
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(updateCounter)
|
||||
} else {
|
||||
this.element.textContent = this.decimalValue && this.targetValue < 10
|
||||
? this.targetValue.toFixed(1)
|
||||
: this.targetValue
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(updateCounter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
this.element.textContent = "Hello World!"
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
import { application } from "./application"
|
||||
|
||||
import HelloController from "./hello_controller"
|
||||
import ShadcnTestController from "./shadcn_test_controller"
|
||||
import CounterController from "./counter_controller"
|
||||
|
||||
application.register("hello", HelloController)
|
||||
application.register("shadcn-test", ShadcnTestController)
|
||||
application.register("counter", CounterController)
|
||||
|
||||
Reference in New Issue
Block a user