package sections import ( "fmt" "github.com/onsonr/sonr/pkg/webui/landing/models" "github.com/onsonr/sonr/pkg/webui/styles/button" ) // Hero Section templ Hero(hero *models.Hero) {
@heroTitle(hero.TitleFirst, hero.TitleEmphasis, hero.TitleSecond)

{ hero.Subtitle }

@button.Primary("/register", "Get Started") @button.Secondary("/learn", "Learn More")
@heroImage(hero.Image) @stats(hero.Stats)
} templ heroTitle(first string, emphasis string, second string) {

{ first } { emphasis }
{ second }

} templ heroImage(hero *models.Image) {
Hero
} templ stats(stats []*models.Stat) {
for _, item := range stats {

{ item.Value }{ item.Denom }

{ item.Label }

}
@counterAnimation()
} func counterXData(value string) string { return fmt.Sprintf("counter(%s)", value) } script counterAnimation() { document.addEventListener('alpine:init', () => { Alpine.data('counter', (target = 0, duration = 3000) => ({ startTimestamp: null, step: null, rawValue: 0, counterValue: 0, target: target, precision: (target % 1 === 0) ? 0 : (target.toString().split('.')[1] || []).length, animationRequestId: null, animationCompleted: false, observer: null, init() { // Intersection observer to watch visibility this.observer = new IntersectionObserver(entries => { entries.forEach(entry => { // Check if element is in view if (entry.isIntersecting && !this.animationCompleted) { this.startAnimation() } }) }) this.observer.observe(this.$el) }, startAnimation() { this.step = (timestamp) => { if (!this.startTimestamp) this.startTimestamp = timestamp const progress = Math.min((timestamp - this.startTimestamp) / duration, 1) const easedProgress = this.easeOut(progress) this.rawValue = parseFloat((easedProgress * this.target).toFixed(this.precision)) this.counterValue = this.rawValue.toFixed(this.precision) if (progress < 1) { this.animationRequestId = window.requestAnimationFrame(this.step) } else { this.animationCompleted = true } } this.animationRequestId = window.requestAnimationFrame(this.step); }, easeOut(t) { return 1 - Math.pow(1 - t, 5) }, destroy() { // Detach the handler, avoiding memory and side-effect leakage this.animationRequestId && window.cancelAnimationFrame(this.step) this.observer && this.observer.disconnect() }, })) }) }