oxios 1.5.2

Oxios Agent OS — Agent Operating System powered by oxi-sdk
import { RotateCcw } from 'lucide-react'
import type { ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { cn } from '@/lib/utils'

interface SectionCardProps {
  /** Section title (already translated). */
  title: string
  /** Section description (already translated). */
  description?: string
  /** Optional icon element. */
  icon?: ReactNode
  /** Section id for `data-section` attr. */
  sectionId: string
  /** Total field count. */
  fieldCount?: number
  /** Whether this section has any unsaved changes. */
  modified?: boolean
  /** Reset the section to server values. */
  onReset?: () => void
  /** Children — the field rows. */
  children: ReactNode
  /** Optional `className` passthrough for the outer Card. */
  className?: string
}

/**
 * Unified section container used by every settings section.
 *
 * Header carries the section title, an optional icon, a description,
 * a small metadata row (field count), and a "reset section" button
 * that only appears when there are unsaved changes.
 *
 * Restart-required information is **not** shown here — it only appears
 * in the DiffPreview modal at save time, so the resting state stays
 * clean and noise-free.
 *
 * The body is a clean stack of `FieldRow`s — separators are drawn by
 * each row's hover/active state, not by hard borders.
 */
export function SectionCard({
  title,
  description,
  icon,
  sectionId,
  fieldCount,
  modified,
  onReset,
  children,
  className,
}: SectionCardProps) {
  const { t } = useTranslation()

  return (
    <Card
      data-section={sectionId}
      data-modified={modified ? 'true' : undefined}
      className={cn(
        'overflow-hidden border transition-shadow',
        // Single-tone surface (spec §6): the whole card — header AND
        // body — sits on --surface-section (muted/30), giving a unified
        // inset-panel look instead of a white card with a tinted header.
        'bg-surface-section',
        'shadow-sm',
        modified && 'ring-1 ring-modified-accent/30 dark:ring-modified-accent/40',
        className,
      )}
    >
      {/* Header */}
      <div
        className={cn(
          'flex flex-col gap-3 border-b px-5 py-4 sm:flex-row sm:items-start sm:gap-4',
          // Single tone: no header gradient — same surface as the body.
        )}
      >
        {/* Title block */}
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2.5">
            {icon && (
              <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
                {icon}
              </span>
            )}
            <h2 className="text-base font-semibold tracking-tight text-foreground">{title}</h2>
            {modified && (
              <span
                aria-label={t('settings.modified')}
                title={t('settings.modified')}
                className="inline-block h-1.5 w-1.5 rounded-full bg-primary"
                data-testid="section-modified-dot"
              />
            )}
          </div>
          {description && (
            <p className="mt-1.5 text-sm text-muted-foreground leading-relaxed">{description}</p>
          )}

          {/* Metadata row */}
          {fieldCount !== undefined && fieldCount > 0 && (
            <div className="mt-3 flex flex-wrap items-center gap-2 text-2xs">
              <span className="text-muted-foreground tabular-nums">
                {fieldCount} {fieldCount === 1 ? 'field' : 'fields'}
              </span>
            </div>
          )}
        </div>

        {/* Reset button (only when modified) */}
        {onReset && (
          <div className="flex items-center gap-2 shrink-0">
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={onReset}
              disabled={!modified}
              className="text-muted-foreground hover:text-foreground"
              data-testid="section-reset"
            >
              <RotateCcw className="h-3.5 w-3.5 mr-1.5" />
              {t('common.reset')}
            </Button>
          </div>
        )}
      </div>

      {/* Body */}
      <CardContent className="px-5 py-4">
        <div className="divide-y divide-border/40">{children}</div>
      </CardContent>
    </Card>
  )
}