develop #3
@@ -1,3 +1,16 @@
|
|||||||
// Entry point for the build script in your package.json
|
// Entry point for the build script in your package.json
|
||||||
import "@hotwired/turbo-rails"
|
import "@hotwired/turbo-rails"
|
||||||
import "./controllers"
|
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))
|
||||||
|
})
|
||||||
|
|||||||
61
app/javascript/components/counter.js
Normal file
61
app/javascript/components/counter.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
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))
|
||||||
|
})
|
||||||
2
app/javascript/controllers/counter_controller.js
Normal file
2
app/javascript/controllers/counter_controller.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
<div class="absolute inset-0 bg-black bg-opacity-40"></div>
|
<div class="absolute inset-0 bg-black bg-opacity-40"></div>
|
||||||
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||||
<h1 class="text-5xl md:text-7xl font-bold text-white mb-6 leading-tight">
|
<h1 class="text-5xl md:text-7xl font-bold text-white mb-6 leading-tight">
|
||||||
Découvrez la nuit parisienne
|
Découvrez les afterworks et soirée
|
||||||
<span class="block text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400">
|
<span class="text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400">
|
||||||
comme jamais
|
à Paris
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-xl md:text-2xl text-gray-200 mb-8 max-w-3xl mx-auto leading-relaxed">
|
<p class="text-xl md:text-2xl text-gray-200 mb-8 max-w-3xl mx-auto leading-relaxed">
|
||||||
@@ -18,6 +18,101 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Metrics -->
|
||||||
|
<section class="bg-gradient-to-br from-gray-900 via-gray-800 to-black py-20">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h2 class="text-4xl md:text-5xl font-bold text-white mb-4">
|
||||||
|
Des chiffres qui parlent
|
||||||
|
</h2>
|
||||||
|
<p class="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||||
|
La plateforme préférée des Parisiens pour vivre la nuit
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 md:gap-12">
|
||||||
|
<!-- Total Events -->
|
||||||
|
<div class="group relative">
|
||||||
|
<div class="relative overflow-hidden rounded-2xl bg-gray-800/60 backdrop-blur-sm border border-gray-700/50 hover:border-purple-500/50 transition-all duration-300 p-8">
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-br from-purple-600/20 to-indigo-600/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="text-5xl md:text-6xl font-light bg-gradient-to-r from-purple-400 via-indigo-400 to-pink-400 bg-clip-text text-transparent mb-3">
|
||||||
|
<span class="counter" data-target="2473">0</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-200 font-mono uppercase tracking-widest text-sm font-medium">
|
||||||
|
Événements organisés
|
||||||
|
</p>
|
||||||
|
<div class="mt-4 h-1 bg-gradient-to-r from-purple-500 via-indigo-500 to-pink-500 rounded-full w-0 group-hover:w-full transition-all duration-500"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Total Users -->
|
||||||
|
<div class="group relative">
|
||||||
|
<div class="relative overflow-hidden rounded-2xl bg-gray-800/60 backdrop-blur-sm border border-gray-700/50 hover:border-purple-500/50 transition-all duration-300 p-8">
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-br from-purple-600/20 to-indigo-600/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="text-5xl md:text-6xl font-light bg-gradient-to-r from-purple-400 via-indigo-400 to-pink-400 bg-clip-text text-transparent mb-3">
|
||||||
|
<span class="counter" data-target="15420">0</span>+
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-200 font-mono uppercase tracking-widest text-sm font-medium">
|
||||||
|
Membres actifs
|
||||||
|
</p>
|
||||||
|
<div class="mt-4 h-1 bg-gradient-to-r from-purple-500 via-indigo-500 to-pink-500 rounded-full w-0 group-hover:w-full transition-all duration-500"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Average Rating -->
|
||||||
|
<div class="group relative">
|
||||||
|
<div class="relative overflow-hidden rounded-2xl bg-gray-800/60 backdrop-blur-sm border border-gray-700/50 hover:border-purple-500/50 transition-all duration-300 p-8">
|
||||||
|
<div class="absolute inset-0 bg-gradient-to-br from-purple-600/20 to-indigo-600/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="text-5xl md:text-6xl font-light bg-gradient-to-r from-purple-400 via-indigo-400 to-pink-400 bg-clip-text text-transparent mb-3">
|
||||||
|
<span class="counter" data-target="4.8" data-decimal="true">0</span>/5
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-200 font-mono uppercase tracking-widest text-sm font-medium">
|
||||||
|
Note moyenne des soirées
|
||||||
|
</p>
|
||||||
|
<div class="mt-4 h-1 bg-gradient-to-r from-purple-500 via-indigo-500 to-pink-500 rounded-full w-0 group-hover:w-full transition-all duration-500"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Additional Stats Row -->
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-6 mt-12">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-3xl font-bold text-purple-300">
|
||||||
|
<span class="counter" data-target="89">0</span>%
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-300 text-sm font-mono uppercase tracking-wide font-medium">Taux de remplissage</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-3xl font-bold text-purple-300">
|
||||||
|
<span class="counter" data-target="12">0</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-300 text-sm font-mono uppercase tracking-wide font-medium">Arrondissements</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-3xl font-bold text-purple-300">
|
||||||
|
<span class="counter" data-target="156">0</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-300 text-sm font-mono uppercase tracking-wide font-medium">Établissements partenaires</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-3xl font-bold text-purple-300">
|
||||||
|
<span class="counter" data-target="98">0</span>%
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-300 text-sm font-mono uppercase tracking-wide font-medium">Satisfaction client</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Quick Search Section -->
|
<!-- Quick Search Section -->
|
||||||
<section id="search" class="bg-gray-900 py-16">
|
<section id="search" class="bg-gray-900 py-16">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|||||||
26
ecosystem.config.js
Normal file
26
ecosystem.config.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "watch-js", // Name of the process
|
||||||
|
script: "bun", // Run npm command
|
||||||
|
args: "run build --watch", // Run build, build:css, and watch:files in sequence
|
||||||
|
watch: false, // Watch for file changes (you can modify this as needed)
|
||||||
|
autorestart: true, // Automatically restart on crash
|
||||||
|
max_restarts: 10, // Maximum number of restarts PM2 will attempt
|
||||||
|
env: {
|
||||||
|
NODE_ENV: "development", // Set environment variables here (optional)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "watch-css", // Name of the process
|
||||||
|
script: "bun", // Run npm command
|
||||||
|
args: "run build:css --watch", // Run build, build:css, and watch:files in sequence
|
||||||
|
watch: false, // Watch for file changes (you can modify this as needed)
|
||||||
|
autorestart: true, // Automatically restart on crash
|
||||||
|
max_restarts: 10, // Maximum number of restarts PM2 will attempt
|
||||||
|
env: {
|
||||||
|
NODE_ENV: "development", // Set environment variables here (optional)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user