SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
1.1 KB · 26 lines tsx
Raw Blame History
1'use client';2import { useEffect, useState } from 'react';3import { cn } from '@/lib/cn';4import { fmtAgo } from '@/lib/format';56/** Green live dot with optional pulse ring. */7export function Dot({ pulse = false, className, tone = 'positive' }: { pulse?: boolean; className?: string; tone?: 'positive' | 'warning' | 'danger' | 'muted' }) {8  return <span className={cn('dot', pulse && 'pulse', tone === 'warning' && 'bg-warning', tone === 'danger' && 'bg-danger', tone === 'muted' && 'bg-ink-3', className)} aria-hidden />;9}1011/** "3 min ago" that re-renders every 30 s. Renders the server value first (no hydration mismatch: same formatting). */12export function LiveAgo({ at, prefix = '', className }: { at: string | null | undefined; prefix?: string; className?: string }) {13  const [now, setNow] = useState<number | null>(null);14  useEffect(() => {15    setNow(Date.now());16    const t = setInterval(() => setNow(Date.now()), 30_000);17    return () => clearInterval(t);18  }, []);19  return (20    <time dateTime={at ?? undefined} className={cn('tnum', className)} suppressHydrationWarning>21      {prefix}22      {fmtAgo(at, now ?? undefined)}23    </time>24  );25}26