{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "status-timestamp",
  "title": "Status Timestamp",
  "description": "Interactive timestamp display with tooltip (simple) or hover-card (rich) variants showing multiple timezone formats",
  "dependencies": [
    "@radix-ui/react-hover-card",
    "date-fns",
    "@date-fns/utc@2.1.0",
    "lucide-react"
  ],
  "registryDependencies": [
    "hover-card",
    "tooltip",
    "https://openstatus.dev/r/use-copy-to-clipboard.json",
    "https://openstatus.dev/r/use-media-query.json"
  ],
  "files": [
    {
      "path": "src/components/blocks/status-timestamp.tsx",
      "content": "\"use client\";\n\nimport { UTCDate } from \"@date-fns/utc\";\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useCopyToClipboard } from \"@/hooks/use-copy-to-clipboard\";\nimport { useMediaQuery } from \"@/hooks/use-media-query\";\nimport { cn } from \"@/lib/utils\";\nimport type { HoverCardContentProps } from \"@radix-ui/react-hover-card\";\nimport { format, formatDistanceToNowStrict } from \"date-fns\";\nimport { Check, Copy } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\n\ntype BaseProps = {\n  date: Date;\n  variant?: \"simple\" | \"rich\";\n  className?: string;\n};\n\ntype SimpleVariantProps = BaseProps &\n  React.ComponentProps<typeof TooltipTrigger> & {\n    variant?: \"simple\";\n  };\n\ntype RichVariantProps = BaseProps &\n  React.ComponentProps<typeof HoverCardTrigger> & {\n    variant: \"rich\";\n    side?: HoverCardContentProps[\"side\"];\n    align?: HoverCardContentProps[\"align\"];\n    alignOffset?: HoverCardContentProps[\"alignOffset\"];\n    sideOffset?: HoverCardContentProps[\"sideOffset\"];\n  };\n\ntype StatusTimestampProps = SimpleVariantProps | RichVariantProps;\n\n/**\n * StatusTimestamp - Polymorphic timestamp display component with timezone support\n *\n * A flexible timestamp component that can display dates in two variants:\n * - **simple**: Shows a tooltip on hover with the formatted date (default)\n * - **rich**: Shows a hover card with local timezone, UTC, and relative time, plus copy-to-clipboard\n *\n * The component automatically detects the user's timezone using `Intl.DateTimeFormat()`\n * and displays the date in both the local timezone and UTC. The rich variant includes\n * a live-updating relative time display (\"2 minutes ago\") that refreshes every second\n * while the hover card is open.\n *\n * Touch device support is built-in for the rich variant, toggling the hover card on tap\n * instead of requiring hover.\n *\n * @param date - The date to display\n * @param variant - Display style: \"simple\" for tooltip, \"rich\" for hover card with details\n * @param side - (rich variant only) Placement of the hover card: \"top\" | \"right\" | \"bottom\" | \"left\"\n * @param align - (rich variant only) Alignment of the hover card: \"start\" | \"center\" | \"end\"\n * @param alignOffset - (rich variant only) Pixel offset for alignment (default: -4)\n * @param sideOffset - (rich variant only) Pixel offset from the trigger\n *\n * @example\n * // Simple variant with tooltip\n * ```tsx\n * <StatusTimestamp date={new Date()} />\n * ```\n *\n * @example\n * // Simple variant with custom children\n * ```tsx\n * <StatusTimestamp date={createdAt}>\n *   Created at\n * </StatusTimestamp>\n * ```\n *\n * @example\n * // Rich variant with hover card showing timezone details\n * ```tsx\n * <StatusTimestamp\n *   date={new Date()}\n *   variant=\"rich\"\n *   side=\"right\"\n * >\n *   2 hours ago\n * </StatusTimestamp>\n * ```\n *\n * @example\n * // Rich variant with custom positioning\n * ```tsx\n * <StatusTimestamp\n *   date={incidentDate}\n *   variant=\"rich\"\n *   side=\"bottom\"\n *   align=\"start\"\n *   alignOffset={0}\n * >\n *   {format(incidentDate, \"MMM d, HH:mm\")}\n * </StatusTimestamp>\n * ```\n */\nexport function StatusTimestamp(props: StatusTimestampProps) {\n  const { date, variant = \"simple\", className, ...rest } = props;\n\n  if (variant === \"rich\") {\n    const {\n      side = \"right\",\n      align = \"start\",\n      alignOffset = -4,\n      sideOffset,\n      children,\n      onClick,\n      ...triggerProps\n    } = rest as Omit<RichVariantProps, \"date\" | \"variant\" | \"className\">;\n\n    return (\n      <RichTimestamp\n        data-slot=\"status-timestamp\"\n        date={date}\n        side={side}\n        align={align}\n        alignOffset={alignOffset}\n        sideOffset={sideOffset}\n        className={className}\n        onClick={onClick}\n        {...triggerProps}\n      >\n        {children}\n      </RichTimestamp>\n    );\n  }\n\n  const { children, ...triggerProps } = rest as Omit<\n    SimpleVariantProps,\n    \"date\" | \"variant\" | \"className\"\n  >;\n\n  return (\n    <SimpleTimestamp\n      data-slot=\"status-timestamp\"\n      date={date}\n      className={className}\n      {...triggerProps}\n    >\n      {children}\n    </SimpleTimestamp>\n  );\n}\nStatusTimestamp.displayName = \"StatusTimestamp\";\n\n/**\n * SimpleTimestamp - Internal tooltip-based timestamp display\n *\n * Displays a formatted timestamp with an underlined, dashed decoration and shows\n * the full formatted date in a tooltip on hover. The timestamp is shown in monospace\n * font with muted foreground color.\n *\n * If no children are provided, displays the date in UTC format. If children are\n * provided, they are used as the trigger text while the tooltip still shows the\n * formatted date in the user's local timezone.\n *\n * @param date - The date to display\n * @param children - Optional custom text to display (falls back to formatted UTC date)\n *\n * @example\n * ```tsx\n * <SimpleTimestamp date={new Date()}>\n *   2 hours ago\n * </SimpleTimestamp>\n * ```\n */\nfunction SimpleTimestamp({\n  date,\n  className,\n  children,\n  ...props\n}: Omit<SimpleVariantProps, \"variant\">) {\n  return (\n    <TooltipProvider>\n      <Tooltip>\n        <TooltipTrigger\n          className={cn(\n            \"text-muted-foreground decoration-muted-foreground/30 font-mono underline decoration-dashed underline-offset-4\",\n            className,\n          )}\n          {...props}\n        >\n          {children || format(new UTCDate(date), \"LLL dd, y HH:mm '(UTC)'\")}\n        </TooltipTrigger>\n        <TooltipContent data-slot=\"status-timestamp-content\">\n          <p className=\"font-mono\">{format(date, \"LLL dd, y HH:mm (z)\")}</p>\n        </TooltipContent>\n      </Tooltip>\n    </TooltipProvider>\n  );\n}\nSimpleTimestamp.displayName = \"SimpleTimestamp\";\n\n/**\n * RichTimestamp - Internal hover card timestamp display with timezone details\n *\n * Displays a hover card with comprehensive timestamp information:\n * - Local timezone timestamp with timezone abbreviation (e.g., \"PST\", \"EST\")\n * - UTC timestamp\n * - Relative time (\"2 hours ago\") that updates every second while open\n *\n * Each row in the hover card is clickable to copy the value to clipboard, with\n * a copy icon that appears on hover and changes to a check mark after copying.\n *\n * Touch device support: On touch devices (detected via `(hover: none)` media query),\n * tapping toggles the hover card open/closed instead of requiring hover.\n *\n * The relative time automatically updates every second while the hover card is\n * open, providing live feedback for recent timestamps.\n *\n * @param date - The date to display\n * @param side - Placement of the hover card (default: \"right\")\n * @param align - Alignment of the hover card (default: \"start\")\n * @param alignOffset - Pixel offset for alignment (default: -4)\n * @param sideOffset - Pixel offset from the trigger\n * @param children - Custom trigger content\n *\n * @example\n * ```tsx\n * <RichTimestamp\n *   date={new Date()}\n *   side=\"bottom\"\n *   align=\"center\"\n * >\n *   Click for details\n * </RichTimestamp>\n * ```\n */\nfunction RichTimestamp({\n  date,\n  side = \"right\",\n  align = \"start\",\n  alignOffset = -4,\n  sideOffset,\n  className,\n  children,\n  onClick,\n  ...props\n}: Omit<RichVariantProps, \"variant\">) {\n  const [open, setOpen] = useState(false);\n  const isTouch = useMediaQuery(\"(hover: none)\");\n  const [_, setRerender] = useState(0);\n\n  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n  const relative = formatDistanceToNowStrict(date, { addSuffix: true });\n  const formatted = format(date, \"LLL dd, y HH:mm:ss\");\n  const utc = format(new UTCDate(date), \"LLL dd, y HH:mm:ss\");\n\n  useEffect(() => {\n    // only setInterval if open\n    if (!open) return;\n\n    const interval = setInterval(() => {\n      setRerender((prev) => prev + 1);\n    }, 1000);\n\n    return () => clearInterval(interval);\n  }, [open]);\n\n  return (\n    <HoverCard openDelay={0} closeDelay={0} open={open} onOpenChange={setOpen}>\n      <HoverCardTrigger\n        className={className}\n        onClick={(e) => {\n          // NOTE: support touch devices\n          if (isTouch) setOpen((prev) => !prev);\n          onClick?.(e);\n        }}\n        {...props}\n      >\n        {children}\n      </HoverCardTrigger>\n      <HoverCardContent\n        data-slot=\"status-timestamp-content\"\n        className=\"z-10 w-auto p-2\"\n        {...{ side, align, alignOffset, sideOffset }}\n      >\n        <dl className=\"flex flex-col gap-1\">\n          <StatusTimestampRow value={formatted} label={timezone} />\n          <StatusTimestampRow value={utc} label=\"UTC\" />\n          <StatusTimestampRow value={relative} label=\"Relative\" />\n        </dl>\n      </HoverCardContent>\n    </HoverCard>\n  );\n}\nRichTimestamp.displayName = \"RichTimestamp\";\n\n/**\n * StatusTimestampRow - Internal component for hover card timestamp rows\n *\n * Displays a single row in the rich timestamp hover card with a label (e.g., \"UTC\")\n * and value (e.g., \"Jan 15, 2024 10:30:45\"). The entire row is clickable to copy\n * the value to clipboard.\n *\n * The copy icon appears on hover and changes to a check mark after successful copy.\n * A toast notification is shown when the value is copied.\n *\n * @param value - The timestamp string to display and copy\n * @param label - The label for this timestamp (e.g., \"UTC\", \"PST\", \"Relative\")\n */\nfunction StatusTimestampRow({\n  value,\n  label,\n}: {\n  value: string;\n  label: string;\n}) {\n  const { copy, isCopied } = useCopyToClipboard();\n\n  return (\n    <div\n      data-slot=\"status-timestamp-row\"\n      className=\"group flex items-center justify-between gap-4 text-sm\"\n      onClick={(e) => {\n        e.stopPropagation();\n        copy(value, { withToast: true });\n      }}\n    >\n      <dt className=\"text-muted-foreground\">{label}</dt>\n      <dd className=\"flex items-center gap-1 truncate font-mono\">\n        <span className=\"invisible group-hover:visible\">\n          {!isCopied ? (\n            <Copy className=\"h-3 w-3\" />\n          ) : (\n            <Check className=\"h-3 w-3\" />\n          )}\n        </span>\n        {value}\n      </dd>\n    </div>\n  );\n}\nStatusTimestampRow.displayName = \"StatusTimestampRow\";\n",
      "type": "registry:ui",
      "target": "components/blocks/status-timestamp.tsx"
    }
  ],
  "type": "registry:block"
}