spb/earth-now Public License
earth-now.co — real-time planetary dashboard: live world metrics modeled, not streamed.
TypeScript 93%
Shell 2.3%
SQL 1.4%
JavaScript 1.3%
Dockerfile 1.2%
CSS 0.8%
1/**2 * earth-now.co3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: apps/web/components/FitValue.tsx6 * Purpose: Overflow-proof ticking value — measures and scales the digit line to always fit its container (mobile and desktop)7 */89"use client";1011import { useEffect, useRef } from "react";1213export interface FitValueProps {14 text: string;15 className?: string;16}1718/**19 * Renders a single-line value that NEVER overflows: the inner span is scaled20 * down (transform, left-anchored) whenever it is wider than the container.21 * With tabular-nums the width only depends on the character count, so we22 * re-measure on length changes and container resizes — not on every rAF tick.23 */24export default function FitValue({ text, className = "" }: FitValueProps) {25 const containerRef = useRef<HTMLDivElement>(null);26 const spanRef = useRef<HTMLSpanElement>(null);27 const lastLength = useRef(-1);2829 useEffect(() => {30 const container = containerRef.current;31 const span = spanRef.current;32 if (container === null || span === null) return;3334 const fit = () => {35 // scale = min(1, available / natural); measured unscaled via scrollWidth.36 const natural = span.scrollWidth;37 const available = container.clientWidth;38 const scale = natural > 0 ? Math.min(1, available / natural) : 1;39 span.style.transform = scale < 1 ? `scale(${scale})` : "";40 };4142 fit();43 const observer = new ResizeObserver(fit);44 observer.observe(container);45 // Re-fit when the digit count changes (value crossed a power of ten).46 const id = window.setInterval(() => {47 const len = span.textContent?.length ?? 0;48 if (len !== lastLength.current) {49 lastLength.current = len;50 fit();51 }52 }, 500);53 return () => {54 observer.disconnect();55 window.clearInterval(id);56 };57 }, []);5859 return (60 <div ref={containerRef} className="w-full overflow-hidden">61 <span62 ref={spanRef}63 className={`inline-block origin-bottom-left whitespace-nowrap ${className}`}64 >65 {text}66 </span>67 </div>68 );69}70