"use client";
import { useState, useSyncExternalStore } from "react";
import { defineCatalog } from "@json-render/core";
import { schema, defineRegistry } from "@json-render/react";
import {
threeComponentDefinitions,
threeComponents,
ThreeCanvas,
} from "@json-render/react-three-fiber";
import { scenes } from "./scenes";
const catalog = defineCatalog(schema, {
components: {
...threeComponentDefinitions,
},
actions: {},
});
const { registry } = defineRegistry(catalog, {
components: {
...threeComponents,
},
});
function highlightJson(json: string): string {
return json.replace(
/("(?:\\.|[^"\\])*")\s*(:)|("(?:\\.|[^"\\])*")|([-+]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b|\bnull\b)|([{}[\]:,])/g,
(_, key, colon, str, num, lit, punct) => {
if (key) return `${key}${colon}`;
if (str) return `${str}`;
if (num) return `${num}`;
if (lit) return `${lit}`;
if (punct) return `${punct}`;
return _;
},
);
}
const MOBILE_BREAKPOINT = 768;
function subscribeToResize(cb: () => void) {
window.addEventListener("resize", cb);
return () => window.removeEventListener("resize", cb);
}
function getIsMobile() {
return typeof window !== "undefined"
? window.innerWidth < MOBILE_BREAKPOINT
: false;
}
function useIsMobile() {
return useSyncExternalStore(subscribeToResize, getIsMobile, () => false);
}
const LIST_WIDTH = 220;
const JSON_WIDTH = 380;
const HEADER_HEIGHT = 40;
const headerStyle: React.CSSProperties = {
height: HEADER_HEIGHT,
display: "flex",
alignItems: "center",
padding: "0 16px",
fontSize: 11,
fontWeight: 600,
color: "#555",
letterSpacing: "0.08em",
textTransform: "uppercase",
fontFamily: "ui-monospace, monospace",
borderBottom: "1px solid #1e1e1e",
flexShrink: 0,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
boxSizing: "border-box",
};
function DesktopLayout() {
const [selectedIndex, setSelectedIndex] = useState(0);
const selected = scenes[selectedIndex]!;
return (
Scenes
{scenes.map((scene, i) => (
))}
);
}
function MobileLayout() {
const [selectedIndex, setSelectedIndex] = useState(0);
const [showJson, setShowJson] = useState(false);
const [showScenes, setShowScenes] = useState(false);
const selected = scenes[selectedIndex]!;
return (
{selected.description}
{showScenes && (
<>
setShowScenes(false)}
style={{
position: "absolute",
inset: 0,
background: "rgba(0,0,0,0.5)",
zIndex: 10,
}}
/>
Scenes
{scenes.map((scene, i) => (
))}
>
)}
{showJson && (
<>
setShowJson(false)}
style={{
position: "absolute",
inset: 0,
background: "rgba(0,0,0,0.5)",
zIndex: 10,
}}
/>
>
)}
);
}
export default function Page() {
const isMobile = useIsMobile();
return isMobile ?
:
;
}