import Link from 'next/link'; import type { ReactNode } from 'react'; import { cn } from '@/lib/cn'; import { DASH } from '@/lib/format'; /* Dense admin primitives on the shared tokens. No marketing, no cards. */ const chip = 'inline-flex items-center whitespace-nowrap rounded-[3px] px-1.5 py-[1px] text-[11px] font-medium leading-4 tracking-wide'; const HEALTH: Record = { ok: 'text-positive bg-positive-soft', success: 'text-positive bg-positive-soft', done: 'text-positive bg-positive-soft', approved: 'text-positive bg-positive-soft', extracted: 'text-positive bg-positive-soft', active: 'text-positive bg-positive-soft', degraded: 'text-warning bg-warning-soft', partial: 'text-warning bg-warning-soft', skipped: 'text-warning bg-warning-soft', queued: 'text-accent bg-accent-soft', running: 'text-accent bg-accent-soft', pending: 'text-accent bg-accent-soft', failing: 'text-danger bg-danger-soft', failed: 'text-danger bg-danger-soft', error: 'text-danger bg-danger-soft', dead: 'text-danger bg-danger-soft', rejected: 'text-danger bg-danger-soft', schema_error: 'text-danger bg-danger-soft', blocked: 'text-danger bg-danger-soft', disabled: 'text-ink-3 bg-surface-2', unknown: 'text-ink-3 bg-surface-2', }; /** Health / status chip: ok → positive · degraded → warning · failing → danger · disabled/unknown → muted. */ export function StatusChip({ value, className }: { value: string | null | undefined; className?: string }) { if (!value) return {DASH}; return {value}; } export function KindChip({ value, className }: { value: string; className?: string }) { return {value}; } export function Bool({ v }: { v: boolean | null | undefined }) { if (v === null || v === undefined) return {DASH}; return {v ? 'yes' : 'no'}; } /** Inline notice from `?notice=&level=` after a server action. */ export function Notice({ notice, level }: { notice?: string; level?: string }) { if (!notice) return null; const err = level === 'error'; return (

{notice}

); } /** Pretty JSON in a scrollable block; never dumps undefined/null as text. */ export function JsonPre({ value, className, maxHeight = '24rem' }: { value: unknown; className?: string; maxHeight?: string }) { if (value === null || value === undefined) return

none

; const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2); return (
      {text}
    
); } /** Small action button used inside server-action forms. */ export function ActionButton({ children, tone = 'neutral', className, disabled, title }: { children: ReactNode; tone?: 'neutral' | 'accent' | 'danger' | 'positive'; className?: string; disabled?: boolean; title?: string }) { return ( ); } /** Title line for an admin section. */ export function AdminTitle({ title, count, children, lede }: { title: string; count?: ReactNode; children?: ReactNode; lede?: ReactNode }) { return (

{title} {count !== undefined && {count}}

{lede &&

{lede}

}
{children &&
{children}
}
); } /** Compact GET filter form (selects/text) for admin listings. */ export function AdminFilters({ action, fields, className }: { action: string; fields: ({ kind: 'select'; name: string; label: string; value?: string; options: { value: string; label: string }[]; any?: string } | { kind: 'text'; name: string; label: string; value?: string; placeholder?: string } | { kind: 'hidden'; name: string; value: string })[]; className?: string }) { const cls = 'h-9 w-full border border-rule bg-surface px-2 text-xs text-ink focus:border-accent focus:outline-none'; return (
{fields.map((f) => f.kind === 'hidden' ? ( ) : ( ), )}
Reset
); } export function Mono({ children, className, title }: { children: ReactNode; className?: string; title?: string }) { return ( {children} ); } /** Truncate long text with the full text as title. */ export function Trunc({ text, max = 80, className }: { text: string | null | undefined; max?: number; className?: string }) { if (!text) return {DASH}; return ( max ? text : undefined}> {text.length > max ? `${text.slice(0, max)}…` : text} ); }