awa-ui 0.5.2

Web UI and JSON API for the Awa job queue
Documentation
/**
 * Syntax-highlighted JSON viewer. Renders JSON with coloured
 * keys, strings, numbers, booleans, and nulls.
 */

interface JsonViewProps {
  data: unknown;
}

export function JsonView({ data }: JsonViewProps) {
  return (
    <pre className="overflow-auto rounded-md bg-muted p-4 font-mono text-[13px] leading-relaxed">
      <JsonNode value={data} indent={0} />
    </pre>
  );
}

function JsonNode({ value, indent }: { value: unknown; indent: number }) {
  if (value === null) {
    return <span className="text-muted-fg italic">null</span>;
  }

  if (typeof value === "boolean") {
    return (
      <span className="text-info-subtle-fg font-semibold">
        {value ? "true" : "false"}
      </span>
    );
  }

  if (typeof value === "number") {
    return <span className="text-warning-subtle-fg">{value}</span>;
  }

  if (typeof value === "string") {
    return <span className="text-success-subtle-fg">"{value}"</span>;
  }

  if (Array.isArray(value)) {
    if (value.length === 0) return <span>{"[]"}</span>;
    const pad = "  ".repeat(indent);
    const innerPad = "  ".repeat(indent + 1);
    return (
      <>
        {"[\n"}
        {value.map((item, i) => (
          <span key={i}>
            {innerPad}
            <JsonNode value={item} indent={indent + 1} />
            {i < value.length - 1 ? ",\n" : "\n"}
          </span>
        ))}
        {pad}
        {"]"}
      </>
    );
  }

  if (typeof value === "object") {
    const entries = Object.entries(value as Record<string, unknown>);
    if (entries.length === 0) return <span>{"{}"}</span>;
    const pad = "  ".repeat(indent);
    const innerPad = "  ".repeat(indent + 1);
    return (
      <>
        {"{\n"}
        {entries.map(([key, val], i) => (
          <span key={key}>
            {innerPad}
            <span className="text-primary-subtle-fg">"{key}"</span>
            {": "}
            <JsonNode value={val} indent={indent + 1} />
            {i < entries.length - 1 ? ",\n" : "\n"}
          </span>
        ))}
        {pad}
        {"}"}
      </>
    );
  }

  return <span>{String(value)}</span>;
}