Skip to content

Commit 4f7bdcb

Browse files
committed
feat: data type viewer
1 parent e8a9219 commit 4f7bdcb

File tree

3 files changed

+98
-18
lines changed

3 files changed

+98
-18
lines changed

src/App.tsx

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from "react";
1+
import { useEffect, useMemo } from "react";
22
import { JsonViewer } from "@textea/json-viewer";
33
import { Sidebar } from "./components/sidebar";
44
import { Input } from "@/components/ui/input";
@@ -20,21 +20,17 @@ export default function App() {
2020
if (apiVersion === "v1") Y.applyUpdate(ydoc, buf);
2121
if (apiVersion === "v2") Y.applyUpdateV2(ydoc, buf);
2222
}
23-
displayOptionStore.setState({ display: ydoc });
23+
displayOptionStore.setState({ display: ydoc, displayError: null });
2424
// @ts-expect-error expose ydoc for advance debug
2525
window.currentDoc = ydoc;
2626
} catch (e) {
27-
displayOptionStore.setState({ display: e });
27+
// @ts-expect-error expose ydoc for advance debug
28+
window.currentDoc = null;
29+
ydoc.destroy();
30+
displayOptionStore.setState({ display: null, displayError: e });
2831
}
2932

30-
if (
31-
typeof prev === "object" &&
32-
prev &&
33-
"destroy" in prev &&
34-
typeof prev.destroy === "function"
35-
) {
36-
prev.destroy();
37-
}
33+
if (prev && prev.destroy) prev.destroy();
3834
}, [inputBuffer, apiVersion]);
3935

4036
return (
@@ -50,17 +46,19 @@ export default function App() {
5046
}
5147
className="mb-4 bg-gray-800 text-white border-gray-700"
5248
/>
53-
<div className="flex-1 overflow-auto bg-gray-800 rounded-lg p-4 [&>div]:px-4 [&>div]:py-2">
54-
<Viewer />
49+
<div className="flex-1 gap-4 grid grid-cols-2 overflow-auto bg-gray-800 rounded-lg p-4 [&>div]:px-4 [&>div]:py-2">
50+
<MainViewer />
51+
<SideViewer />
5552
</div>
5653
</main>
5754
</div>
5855
);
5956
}
6057

61-
function Viewer() {
58+
function MainViewer() {
6259
const {
6360
display,
61+
displayError,
6462
indentWidth,
6563
enableClipboard,
6664
displaySize,
@@ -69,7 +67,46 @@ function Viewer() {
6967
return (
7068
<JsonViewer
7169
theme="dark"
72-
value={display}
70+
value={displayError ?? display}
71+
indentWidth={indentWidth}
72+
enableClipboard={enableClipboard}
73+
displayDataTypes={displayDataTypes}
74+
displaySize={displaySize}
75+
defaultInspectDepth={3}
76+
/>
77+
);
78+
}
79+
80+
function SideViewer() {
81+
const {
82+
display,
83+
displayError,
84+
indentWidth,
85+
enableClipboard,
86+
displaySize,
87+
displayDataTypes,
88+
} = useStore(displayOptionStore);
89+
const getApiType = useStore(yDocOptionStore, (s) => s.getApiType);
90+
const contentDisplay = useMemo(() => {
91+
if (!display) return null;
92+
try {
93+
const ydoc = new Y.Doc();
94+
Y.applyUpdateV2(ydoc, Y.encodeStateAsUpdateV2(display));
95+
const displayObj: Record<string, unknown> = {};
96+
for (const key of ydoc.share.keys()) {
97+
displayObj[key] = ydoc[getApiType](key);
98+
}
99+
ydoc.destroy();
100+
return displayObj;
101+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
102+
} catch (e) {
103+
return null;
104+
}
105+
}, [display, getApiType]);
106+
return (
107+
<JsonViewer
108+
theme="dark"
109+
value={displayError ?? contentDisplay}
73110
indentWidth={indentWidth}
74111
enableClipboard={enableClipboard}
75112
displayDataTypes={displayDataTypes}

src/components/sidebar.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { Switch } from "@/components/ui/switch";
33
import { Label } from "@/components/ui/label";
44
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
55
import { useStore } from "zustand";
6-
import { displayOptionStore, yDocOptionStore } from "@/lib/store";
6+
import {
7+
displayOptionStore,
8+
GetApi,
9+
getApis,
10+
yDocOptionStore,
11+
} from "@/lib/store";
712

813
export function Sidebar() {
914
return (
@@ -16,7 +21,7 @@ export function Sidebar() {
1621
}
1722

1823
function YDocOptions() {
19-
const { apiVersion } = useStore(yDocOptionStore);
24+
const { apiVersion, getApiType } = useStore(yDocOptionStore);
2025
return (
2126
<>
2227
<h3 className="text-lg font-semibold mt-2">Y.Doc Options</h3>
@@ -51,6 +56,30 @@ function YDocOptions() {
5156
</div>
5257
</RadioGroup>
5358
</div>
59+
60+
<h4 className="text-sm font-semibold">View Data As</h4>
61+
<div className="flex items-center space-x-2">
62+
<RadioGroup
63+
value={`option-${getApiType}`}
64+
onValueChange={(v) =>
65+
yDocOptionStore.setState({
66+
getApiType: v.split("-")[1] as GetApi,
67+
})
68+
}
69+
>
70+
{getApis.map((k) => (
71+
<div key={k} className="flex items-center">
72+
<Label
73+
htmlFor={`option-${k}`}
74+
className="cursor-pointer flex gap-2 justify-center items-center"
75+
>
76+
<RadioGroupItem value={`option-${k}`} id={`option-${k}`} />
77+
<code>{k}</code>
78+
</Label>
79+
</div>
80+
))}
81+
</RadioGroup>
82+
</div>
5483
</>
5584
);
5685
}

src/lib/store.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import { createStore } from "zustand";
22
import { persist } from "zustand/middleware";
3+
import type * as Y from "yjs";
4+
5+
export const getApis = [
6+
"getArray",
7+
"getMap",
8+
"getText",
9+
"getXmlElement",
10+
"getXmlFragment",
11+
] as const;
12+
export type GetApi = (typeof getApis)[number];
313

414
interface DisplayOptionStore {
5-
display: unknown;
15+
display: Y.Doc | null;
16+
displayError: unknown;
617
indentWidth: number;
718
enableClipboard: boolean;
819
displayDataTypes: boolean;
@@ -12,12 +23,14 @@ interface DisplayOptionStore {
1223
interface YDocOptionStore {
1324
inputBuffer: string;
1425
apiVersion: "v1" | "v2";
26+
getApiType: GetApi;
1527
}
1628

1729
export const displayOptionStore = createStore<DisplayOptionStore>()(
1830
persist<DisplayOptionStore>(
1931
() => ({
2032
display: null,
33+
displayError: null,
2134
indentWidth: 4,
2235
enableClipboard: true,
2336
displayDataTypes: false,
@@ -34,6 +47,7 @@ export const yDocOptionStore = createStore<YDocOptionStore>()(
3447
() => ({
3548
inputBuffer: "",
3649
apiVersion: "v1",
50+
getApiType: "getArray",
3751
}),
3852
{ name: "ydoc-inspector-ydoc-option" },
3953
),

0 commit comments

Comments
 (0)