File size: 1,724 Bytes
7c5ed63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { useState, type ReactNode } from 'react';

interface SizePreviewProps {
  label?: string;
  /** Byte/char count for the dim label */
  sizeBytes: number;
  /** Preview text shown when collapsed (first ~200 chars) */
  preview?: string;
  /** Full content renderer */
  children: ReactNode;
  /** Start expanded if true */
  defaultOpen?: boolean;
}

export function SizePreview({
  label = 'payload',
  sizeBytes,
  preview,
  children,
  defaultOpen = false,
}: SizePreviewProps) {
  const [open, setOpen] = useState(defaultOpen);
  const size = formatBytes(sizeBytes);
  return (
    <div className="my-1 border border-border bg-surface-0">
      <button
        onClick={() =>{  setOpen((v) => !v); }}
        className="flex w-full items-center justify-between gap-2 px-2 py-1 font-mono text-[11px] text-fg-2 hover:bg-surface-2 hover:text-fg-1"
      >
        <span className="flex items-center gap-2">
          <span className="text-fg-3">{open ? '▾' : '▸'}</span>
          <span className="uppercase tracking-[0.08em]">{label}</span>
          <span className="text-fg-3 tabular">{size}</span>
        </span>
        {!open && preview ? (
          <span className="truncate text-fg-3 font-mono text-[11px]">
            {preview.slice(0, 120)}
            {preview.length > 120 ? '…' : ''}
          </span>
        ) : null}
      </button>
      {open ? (
        <div className="border-t border-border px-2 py-1 font-mono text-[12px]">
          {children}
        </div>
      ) : null}
    </div>
  );
}

export function formatBytes(n: number): string {
  if (n < 1024) return `${n}B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
  return `${(n / 1024 / 1024).toFixed(2)}MB`;
}