TypeScript · 1824 bytes Raw Blame History
1 import { useState } from "react";
2
3 interface AttachmentCardProps {
4 at: string;
5 attachmentType: string;
6 hookName: string | null;
7 text: string;
8 }
9
10 export function AttachmentCard({
11 at,
12 attachmentType,
13 hookName,
14 text,
15 }: AttachmentCardProps) {
16 const [expanded, setExpanded] = useState(false);
17 const preview = firstLine(text);
18
19 return (
20 <div className="rounded border border-border/60 bg-bg-1/40 px-4 py-2 text-[12px]">
21 <button
22 type="button"
23 onClick={() => setExpanded((x) => !x)}
24 className="flex w-full items-start gap-3 text-left"
25 >
26 <span className="mt-0.5 text-[10px] text-fg-3">📎</span>
27 <span className="min-w-0 flex-1">
28 <span className="flex items-center gap-2 text-[10px] uppercase tracking-wide text-fg-3">
29 <span>{attachmentType}</span>
30 {hookName && (
31 <>
32 <span></span>
33 <span className="font-mono">{hookName}</span>
34 </>
35 )}
36 <span></span>
37 <span>{formatAt(at)}</span>
38 </span>
39 <span className="block truncate text-fg-2">
40 {preview || "(empty)"}
41 </span>
42 </span>
43 <span className="shrink-0 text-[10px] text-fg-3">
44 {expanded ? "hide" : "show"}
45 </span>
46 </button>
47 {expanded && text && (
48 <pre className="mt-2 max-h-64 overflow-auto whitespace-pre-wrap rounded border border-border bg-bg-2 p-2 font-mono text-[11px] text-fg-2">
49 {text}
50 </pre>
51 )}
52 </div>
53 );
54 }
55
56 function firstLine(s: string): string {
57 const i = s.indexOf("\n");
58 return i >= 0 ? s.slice(0, i) : s;
59 }
60
61 function formatAt(iso: string): string {
62 try {
63 return new Date(iso).toLocaleString();
64 } catch {
65 return iso;
66 }
67 }