tangled
alpha
login
or
join now
futur.blue
/
pdsls
forked from
pds.ls/pdsls
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
cid link blob url
handle.invalid
4 months ago
c433fae1
2e806994
verified
This commit was signed with the committer's
known signature
.
handle.invalid
SSH Key Fingerprint:
SHA256:mBrT4x0JdzLpbVR95g1hjI1aaErfC02kmLRkPXwsYCk=
+61
-27
1 changed file
expand all
collapse all
unified
split
src
components
json.tsx
+61
-27
src/components/json.tsx
···
1
1
-
import { isDid, isNsid, Nsid } from "@atcute/lexicons/syntax";
1
1
+
import { isCid, isDid, isNsid, Nsid } from "@atcute/lexicons/syntax";
2
2
import { A, useNavigate, useParams } from "@solidjs/router";
3
3
import { createEffect, createSignal, ErrorBoundary, For, Show } from "solid-js";
4
4
import { setNotif } from "../layout";
···
15
15
mimeType: string;
16
16
}
17
17
18
18
-
const JSONString = ({ data, isType }: { data: string; isType?: boolean }) => {
18
18
+
const JSONString = (props: {
19
19
+
data: string;
20
20
+
isType?: boolean;
21
21
+
isLink?: boolean;
22
22
+
parentIsBlob?: boolean;
23
23
+
}) => {
19
24
const navigate = useNavigate();
25
25
+
const params = useParams();
20
26
21
27
const isURL =
22
28
URL.canParse ??
···
49
55
return (
50
56
<span>
51
57
"
52
52
-
<For each={data.split(/(\s)/)}>
58
58
+
<For each={props.data.split(/(\s)/)}>
53
59
{(part) => (
54
60
<>
55
61
{ATURI_RE.test(part) ?
···
60
66
<A class="text-blue-400 hover:underline active:underline" href={`/at://${part}`}>
61
67
{part}
62
68
</A>
63
63
-
: isNsid(part.split("#")[0]) && isType ?
69
69
+
: isNsid(part.split("#")[0]) && props.isType ?
64
70
<button
65
71
type="button"
66
72
onClick={() => handleClick(part)}
···
68
74
>
69
75
{part}
70
76
</button>
77
77
+
: isCid(part) && props.isLink && props.parentIsBlob ?
78
78
+
<A
79
79
+
class="text-blue-400 hover:underline active:underline"
80
80
+
rel="noopener"
81
81
+
target="_blank"
82
82
+
href={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${params.repo}&cid=${part}`}
83
83
+
>
84
84
+
{part}
85
85
+
</A>
71
86
: (
72
87
isURL(part) &&
73
88
["http:", "https:", "web+at:"].includes(new URL(part).protocol) &&
···
97
112
return <span>null</span>;
98
113
};
99
114
100
100
-
const JSONObject = ({ data, repo }: { data: { [x: string]: JSONType }; repo: string }) => {
115
115
+
const JSONObject = (props: {
116
116
+
data: { [x: string]: JSONType };
117
117
+
repo: string;
118
118
+
parentIsBlob?: boolean;
119
119
+
}) => {
101
120
const params = useParams();
102
121
const [hide, setHide] = createSignal(
103
122
localStorage.hideMedia === "true" || params.rkey === undefined,
···
106
125
createEffect(() => {
107
126
if (hideMedia()) setHide(hideMedia());
108
127
});
128
128
+
129
129
+
const isBlob = props.data.$type === "blob";
130
130
+
const isBlobContext = isBlob || props.parentIsBlob;
109
131
110
132
const Obj = ({ key, value }: { key: string; value: JSONType }) => {
111
133
const [show, setShow] = createSignal(true);
···
141
163
"invisible h-0": !show(),
142
164
}}
143
165
>
144
144
-
<JSONValue data={value} repo={repo} isType={key === "$type" ? true : undefined} />
166
166
+
<JSONValue
167
167
+
data={value}
168
168
+
repo={props.repo}
169
169
+
isType={key === "$type"}
170
170
+
isLink={key === "$link"}
171
171
+
parentIsBlob={isBlobContext}
172
172
+
/>
145
173
</span>
146
174
</span>
147
175
);
148
176
};
149
177
150
178
const rawObj = (
151
151
-
<For each={Object.entries(data)}>{([key, value]) => <Obj key={key} value={value} />}</For>
179
179
+
<For each={Object.entries(props.data)}>{([key, value]) => <Obj key={key} value={value} />}</For>
152
180
);
153
181
154
154
-
const blob: AtBlob = data as any;
182
182
+
const blob: AtBlob = props.data as any;
155
183
156
184
if (blob.$type === "blob") {
157
185
return (
···
161
189
<Show when={blob.mimeType.startsWith("image/") && !hide()}>
162
190
<img
163
191
class="h-auto max-h-64 max-w-[16rem] object-contain"
164
164
-
src={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${repo}&cid=${blob.ref.$link}`}
192
192
+
src={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${props.repo}&cid=${blob.ref.$link}`}
165
193
/>
166
194
</Show>
167
195
<Show when={blob.mimeType === "video/mp4" && !hide()}>
168
196
<ErrorBoundary fallback={() => <span>Failed to load video</span>}>
169
169
-
<VideoPlayer did={repo} cid={blob.ref.$link} />
197
197
+
<VideoPlayer did={props.repo} cid={blob.ref.$link} />
170
198
</ErrorBoundary>
171
199
</Show>
172
200
<span
···
187
215
</button>
188
216
</Tooltip>
189
217
</Show>
190
190
-
<Tooltip text="Blob on PDS">
191
191
-
<a
192
192
-
href={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${repo}&cid=${blob.ref.$link}`}
193
193
-
target="_blank"
194
194
-
class={`${!hide() && (blob.mimeType.startsWith("image/") || blob.mimeType === "video/mp4") ? "-mb-1 -ml-0.5" : ""} flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`}
195
195
-
>
196
196
-
<span class="iconify lucide--external-link text-base"></span>
197
197
-
</a>
198
198
-
</Tooltip>
199
218
</span>
200
219
</span>
201
220
</Show>
···
207
226
return rawObj;
208
227
};
209
228
210
210
-
const JSONArray = ({ data, repo }: { data: JSONType[]; repo: string }) => {
229
229
+
const JSONArray = (props: { data: JSONType[]; repo: string; parentIsBlob?: boolean }) => {
211
230
return (
212
212
-
<For each={data}>
231
231
+
<For each={props.data}>
213
232
{(value, index) => (
214
233
<span
215
234
classList={{
216
235
"flex before:content-['-']": true,
217
217
-
"mb-2": value === Object(value) && index() !== data.length - 1,
236
236
+
"mb-2": value === Object(value) && index() !== props.data.length - 1,
218
237
}}
219
238
>
220
239
<span class="ml-[1ch] w-full">
221
221
-
<JSONValue data={value} repo={repo} />
240
240
+
<JSONValue data={value} repo={props.repo} parentIsBlob={props.parentIsBlob} />
222
241
</span>
223
242
</span>
224
243
)}
···
226
245
);
227
246
};
228
247
229
229
-
export const JSONValue = (props: { data: JSONType; repo: string; isType?: boolean }) => {
248
248
+
export const JSONValue = (props: {
249
249
+
data: JSONType;
250
250
+
repo: string;
251
251
+
isType?: boolean;
252
252
+
isLink?: boolean;
253
253
+
parentIsBlob?: boolean;
254
254
+
}) => {
230
255
const data = props.data;
231
231
-
if (typeof data === "string") return <JSONString data={data} isType={props.isType} />;
256
256
+
if (typeof data === "string")
257
257
+
return (
258
258
+
<JSONString
259
259
+
data={data}
260
260
+
isType={props.isType}
261
261
+
isLink={props.isLink}
262
262
+
parentIsBlob={props.parentIsBlob}
263
263
+
/>
264
264
+
);
232
265
if (typeof data === "number") return <JSONNumber data={data} />;
233
266
if (typeof data === "boolean") return <JSONBoolean data={data} />;
234
267
if (data === null) return <JSONNull />;
235
235
-
if (Array.isArray(data)) return <JSONArray data={data} repo={props.repo} />;
236
236
-
return <JSONObject data={data} repo={props.repo} />;
268
268
+
if (Array.isArray(data))
269
269
+
return <JSONArray data={data} repo={props.repo} parentIsBlob={props.parentIsBlob} />;
270
270
+
return <JSONObject data={data} repo={props.repo} parentIsBlob={props.parentIsBlob} />;
237
271
};
238
272
239
273
export type JSONType = string | number | boolean | null | { [x: string]: JSONType } | JSONType[];