import { useState, useCallback } from 'react'; interface JsonViewerProps { content: string; } type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }; function parseJson(content: string): JsonValue | null { try { return JSON.parse(content); } catch { return null; } } export default function JsonViewer({ content }: JsonViewerProps) { const parsed = parseJson(content); const handleCopy = () => { navigator.clipboard.writeText(content); }; if (parsed === null) { return (
Invalid JSON
{content}
); } return (
JSON
); } function JsonNode({ value, path, depth, defaultOpen = false, keyName, }: { value: JsonValue; path: string; depth: number; defaultOpen?: boolean; keyName?: string; }) { if (value === null) return ; if (typeof value === 'boolean') return ; if (typeof value === 'number') return ; if (typeof value === 'string') return ; if (Array.isArray(value)) return ; if (typeof value === 'object') return } path={path} defaultOpen={defaultOpen} />; return null; } function JsonPrimitive({ keyName, depth, value, className }: { keyName?: string; depth: number; value: string; className: string }) { return (
{keyName !== undefined && ( "{keyName}": )} {value}
); } function JsonString({ keyName, depth, value }: { keyName?: string; depth: number; value: string }) { const isLong = value.length > 120; const [expanded, setExpanded] = useState(!isLong); const display = expanded ? value : value.slice(0, 80) + '...'; return (
{keyName !== undefined && ( "{keyName}": )} "{display}" {isLong && ( )}
); } function JsonObject({ keyName, depth, value, path, defaultOpen, }: { keyName?: string; depth: number; value: Record; path: string; defaultOpen?: boolean; }) { const keys = Object.keys(value); const [open, setOpen] = useState(defaultOpen || depth < 2); const handleCopySection = useCallback(() => { navigator.clipboard.writeText(JSON.stringify(value, null, 2)); }, [value]); if (keys.length === 0) { return (
{keyName !== undefined && ( "{keyName}": )} {'{}'}
); } return (
setOpen(!open)} > {keyName !== undefined && ( "{keyName}": )} {'{'} {!open && ( {keys.length} key{keys.length !== 1 ? 's' : ''} )} {!open && {'}'}}
{open && ( <> {keys.map((k) => ( ))}
{'}'}
)}
); } function JsonArray({ keyName, depth, value, path, defaultOpen, }: { keyName?: string; depth: number; value: JsonValue[]; path: string; defaultOpen?: boolean; }) { const [open, setOpen] = useState(defaultOpen || depth < 2); const handleCopySection = useCallback(() => { navigator.clipboard.writeText(JSON.stringify(value, null, 2)); }, [value]); if (value.length === 0) { return (
{keyName !== undefined && ( "{keyName}": )} {'[]'}
); } return (
setOpen(!open)} > {keyName !== undefined && ( "{keyName}": )} {'['} {!open && ( {value.length} item{value.length !== 1 ? 's' : ''} )} {!open && {']'}}
{open && ( <> {value.map((item, i) => ( ))}
{']'}
)}
); }