import { isCid, isDid, isNsid, isResourceUri, Nsid } from "@atcute/lexicons/syntax";
import { A, useNavigate, useParams } from "@solidjs/router";
import { createEffect, createSignal, ErrorBoundary, For, on, Show } from "solid-js";
import { resolveLexiconAuthority } from "../utils/api";
import { hideMedia } from "../views/settings";
import { pds } from "./navbar";
import { addNotification, removeNotification } from "./notification";
import VideoPlayer from "./video-player";
interface AtBlob {
$type: string;
ref: { $link: string };
mimeType: string;
}
const JSONString = (props: {
data: string;
isType?: boolean;
isLink?: boolean;
parentIsBlob?: boolean;
}) => {
const navigate = useNavigate();
const params = useParams();
const isURL =
URL.canParse ??
((url, base) => {
try {
new URL(url, base);
return true;
} catch {
return false;
}
});
const handleClick = async (lex: string) => {
try {
const [nsid, anchor] = lex.split("#");
const authority = await resolveLexiconAuthority(nsid as Nsid);
const hash = anchor ? `#schema:${anchor}` : "#schema";
navigate(`/at://${authority}/com.atproto.lexicon.schema/${nsid}${hash}`);
} catch (err) {
console.error("Failed to resolve lexicon authority:", err);
const id = addNotification({
message: "Could not resolve schema",
type: "error",
});
setTimeout(() => removeNotification(id), 5000);
}
};
return (
"
{(part) => (
<>
{isResourceUri(part) ?
{part}
: isDid(part) ?
{part}
: isNsid(part.split("#")[0]) && props.isType ?
: isCid(part) && props.isLink && props.parentIsBlob && params.repo ?
{part}
: (
isURL(part) &&
["http:", "https:", "web+at:"].includes(new URL(part).protocol) &&
part.split("\n").length === 1
) ?
{part}
: part}
>
)}
"
);
};
const JSONNumber = ({ data }: { data: number }) => {
return {data};
};
const JSONBoolean = ({ data }: { data: boolean }) => {
return {data ? "true" : "false"};
};
const JSONNull = () => {
return null;
};
const JSONObject = (props: {
data: { [x: string]: JSONType };
repo: string;
parentIsBlob?: boolean;
}) => {
const params = useParams();
const [hide, setHide] = createSignal(
localStorage.hideMedia === "true" || params.rkey === undefined,
);
const [mediaLoaded, setMediaLoaded] = createSignal(false);
createEffect(() => {
if (hideMedia()) setHide(hideMedia());
});
createEffect(
on(
hide,
(value) => {
if (value === false) setMediaLoaded(false);
},
{ defer: true },
),
);
const isBlob = props.data.$type === "blob";
const isBlobContext = isBlob || props.parentIsBlob;
const Obj = ({ key, value }: { key: string; value: JSONType }) => {
const [show, setShow] = createSignal(true);
return (
);
};
const rawObj = (
{([key, value]) => }
);
const blob: AtBlob = props.data as any;
if (blob.$type === "blob") {
return (
<>
setMediaLoaded(true)}
/>
Failed to load video}>
setMediaLoaded(true)}
/>
{rawObj}
>
);
}
return rawObj;
};
const JSONArray = (props: { data: JSONType[]; repo: string; parentIsBlob?: boolean }) => {
return (
{(value, index) => (
)}
);
};
export const JSONValue = (props: {
data: JSONType;
repo: string;
isType?: boolean;
isLink?: boolean;
parentIsBlob?: boolean;
}) => {
const data = props.data;
if (typeof data === "string")
return (
);
if (typeof data === "number") return ;
if (typeof data === "boolean") return ;
if (data === null) return ;
if (Array.isArray(data))
return ;
return ;
};
export type JSONType = string | number | boolean | null | { [x: string]: JSONType } | JSONType[];