'use client'
import React from 'react'
import { cn } from '../../utils/cn'
import { Copy01Icon } from '../icons-v2-generated/documents'
import { CheckIcon } from '../icons-v2-generated'
import { useCopyToClipboard } from '../../hooks'
import { ProgressBar } from './progress-bar'
export interface InfoCardFooterData {
/** Leading icon next to the text, expected at 24x24 (e.g. ) */
icon?: React.ReactNode
text: string
/** Trailing icon/logo aligned to the right edge, expected at 24x24 */
logo?: React.ReactNode
/** External resource link rendered below the text row */
link?: {
href: string
/** Defaults to href without the protocol */
label?: string
}
}
export interface InfoCardData {
title?: string
subtitle?: string
icon?: React.ReactNode
items: Array<{
label?: string
value: string | string[]
copyable?: boolean
/** Optional trailing icon/logo (e.g. an SVG) rendered next to the value */
icon?: React.ReactNode
}>
progress?: {
value: number
warningThreshold?: number
criticalThreshold?: number
inverted?: boolean // if true, high values are good (green), low values are bad (red)
}
/** Optional footer rendered below the content, separated by a divider line */
footer?: InfoCardFooterData
}
interface InfoCardProps {
data: InfoCardData
className?: string
}
export function InfoCard({ data, className = '' }: InfoCardProps) {
return (
{/* Header (title + subtitle) and body (rows + progress) are two groups separated by
`gap-l`; the title/subtitle stack tightly and the rows use `gap-xs` — matching the ODS
"Info-card" design. With no title/subtitle, the body is the only group. */}
{(data.title || data.subtitle) && (
{data.title && (
{data.title}
{data.icon}
)}
{data.subtitle && (
{data.subtitle}
{/* Icon lives with the title when present; otherwise it falls to the subtitle so
subtitle-only cards still render it. */}
{!data.title && data.icon}