@@ -33,17 +33,7 @@ title: "Dotenvx Ops"
3333 </div >
3434 </section >
3535
36- <section class =" w-full max-w-7xl mx-auto px-1 md:px-6 mt-44 md:mt-64 lg:mt-[18rem] mb-32 sm:mb-48 md:mb-64 lg:mb-[18rem] " data-ops-signups-trigger >
37- <div class =" relative w-full overflow-hidden rounded-t-[0.9rem] md:rounded-t-[1.1rem] bg-black pt-14 md:pt-20 pb-14 md:pb-20 " >
38- <div class="pointer-events-none absolute left-1/2 top-1/2 h-44 md:h-56 w-[72%] -translate-x-1/2 -translate-y-1/2 bg-[radial-gradient(ellipse_at_center,rgba(112,154,210,0.18)_0%,rgba(112,154,210,0.08)_38%,rgba(0,0,0,0)_74%)] blur-[2px]" aria-hidden="true"></div>
39- <div class="relative z-10 text-center">
40- <div class="mb-4 md:mb-5 text-[0.68rem] md:text-xs font-semibold tracking-[0.1em] uppercase text-zinc-500 dark:text-zinc-400">TRUSTED BY DEVELOPERS</div>
41- <p class="mx-auto max-w-[36ch] text-center text-3xl md:text-4xl leading-tight font-medium tracking-[-0.01em] text-zinc-200">
42- <span class="inline-block text-right tabular-nums" data-ops-signups-count>426</span> developers signed up last month.
43- </p>
44- </div>
45- </div >
46- </section >
36+ {% include components/trust-signups.html section_classes="w-full max-w-7xl mx-auto px-1 md: px-6 mt-44 md: mt-64 lg: mt- [ 18rem] mb-32 sm: mb-48 md: mb-64 lg: mb- [ 18rem] " %}
4737
4838<section class =" w-full max-w-5xl mx-auto px-6 mt-8 md:mt-16 lg:mt-20 mb-44 md:mb-64 lg:mb-[18rem] " >
4939 <div class =" text-center max-w-3xl mx-auto " >
@@ -347,107 +337,4 @@ title: "Dotenvx Ops"
347337})();
348338</script >
349339
350- <script >
351- (() => {
352- const countEls = document .querySelectorAll (' [data-ops-signups-count]' );
353- if (! countEls .length ) return ;
354-
355- const parseCount = (value ) => {
356- if (value === null || value === undefined ) return NaN ;
357- const normalized = String (value).replace (/ ,/ g , ' ' ).trim ();
358- return Number .parseInt (normalized, 10 );
359- };
360-
361- const formatCount = (value ) => value .toLocaleString (' en-US' );
362-
363- const animateSignups = (targetValue ) => {
364- const target = parseCount (targetValue);
365- if (! Number .isFinite (target)) return ;
366-
367- const initialValue = parseCount (countEls[0 ].textContent );
368- const start = Number .isFinite (initialValue) ? initialValue : target;
369- if (target <= start) {
370- const finalText = formatCount (target);
371- countEls .forEach ((el ) => {
372- el .textContent = finalText;
373- });
374- return ;
375- }
376-
377- const durationMs = 2500 ;
378- const easeOutCubic = (t ) => 1 - Math .pow (1 - t, 3 );
379- const startAt = performance .now ();
380-
381- const tick = (now ) => {
382- const elapsed = now - startAt;
383- const progress = Math .min (1 , elapsed / durationMs);
384- const eased = easeOutCubic (progress);
385- const nextValue = Math .round (start + (target - start) * eased);
386- const nextText = formatCount (nextValue);
387-
388- countEls .forEach ((el ) => {
389- el .textContent = nextText;
390- });
391-
392- if (progress < 1 ) {
393- requestAnimationFrame (tick);
394- }
395- };
396-
397- requestAnimationFrame (tick);
398- };
399-
400- const updateSignups = (value ) => {
401- if (! value) return ;
402- animateSignups (value);
403- };
404-
405- const fallbackText = countEls[0 ].textContent ;
406- if (fallbackText) {
407- const fallbackValue = parseCount (fallbackText);
408- const normalizedFallback = Number .isFinite (fallbackValue) ? fallbackValue : 426 ;
409- countEls .forEach ((el ) => {
410- el .textContent = formatCount (normalizedFallback);
411- });
412- }
413-
414- const start = () => {
415- fetch (' https://ops.dotenvx.com/public/stats' , { method: ' GET' })
416- .then ((response ) => {
417- if (! response .ok ) throw new Error (` stats request failed: ${ response .status } ` );
418- return response .json ();
419- })
420- .then ((data ) => {
421- updateSignups (data && data .signups );
422- })
423- .catch (() => {
424- // Keep fallback count from markup.
425- });
426- };
427-
428- const triggerEl = document .querySelector (' [data-ops-signups-trigger]' );
429- if (! triggerEl) {
430- start ();
431- return ;
432- }
433-
434- if (! (' IntersectionObserver' in window )) {
435- start ();
436- return ;
437- }
438-
439- let started = false ;
440- const observer = new IntersectionObserver ((entries ) => {
441- if (started) return ;
442- entries .forEach ((entry ) => {
443- if (! started && entry .isIntersecting ) {
444- started = true ;
445- observer .disconnect ();
446- start ();
447- }
448- });
449- }, { threshold: 0.35 });
450-
451- observer .observe (triggerEl);
452- })();
453- </script >
340+ {% include components/trust-signups-script.html %}
0 commit comments