Lou·Ka — tous les logements à louer du Québec, un seul endroit.
HTML 98.9%
Python 0.6%
1// -----------------------------------------------------------------------------2// Lou-Ka — Agrégateur de logements à louer (province de Québec)3// Auteur : Simon-Pierre Boucher — contact@spboucher.ai4// live.ts : hooks « données vivantes » partagés (accueil, court terme)5// -----------------------------------------------------------------------------6import { useEffect, useState } from "react";78/** Compteur animé du héro (~0,9 s, easing cubique) — l'impression d'un vrai9 moteur qui indexe. Respecte prefers-reduced-motion (valeur directe). */10export function useCountUp(target: number | null | undefined, ms = 900): string | null {11 const [v, setV] = useState<number | null>(null);12 useEffect(() => {13 if (target == null) return;14 if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { setV(target); return; }15 let raf = 0;16 const t0 = performance.now();17 const step = (t: number) => {18 const p = Math.min(1, (t - t0) / ms);19 setV(Math.round(target * (1 - Math.pow(1 - p, 3))));20 if (p < 1) raf = requestAnimationFrame(step);21 };22 raf = requestAnimationFrame(step);23 return () => cancelAnimationFrame(raf);24 }, [target, ms]);25 return v == null ? null : v.toLocaleString("fr-CA");26}2728/** « il y a X s » vivant — re-rendu chaque seconde tant que le ts existe. */29export function useAgo(ts: number | null): string | null {30 const [, tick] = useState(0);31 useEffect(() => {32 if (ts == null) return;33 const id = setInterval(() => tick((x) => x + 1), 1000);34 return () => clearInterval(id);35 }, [ts]);36 if (ts == null) return null;37 const s = Math.max(0, Math.floor(Date.now() / 1000 - ts));38 if (s < 90) return `il y a ${s} s`;39 if (s < 5400) return `il y a ${Math.round(s / 60)} min`;40 return `il y a ${Math.round(s / 3600)} h`;41}42