+6
-3
src/components/create.tsx
+6
-3
src/components/create.tsx
···
172
></span>
173
<span>{props.create ? "Creating" : "Editing"} record</span>
174
</div>
175
-
<button onclick={() => setOpenDialog(false)} class="flex items-center">
176
-
<span class="iconify lucide--x text-lg hover:text-neutral-500 dark:hover:text-neutral-400"></span>
177
</button>
178
</div>
179
<form ref={formRef} class="flex flex-col gap-y-2">
···
186
<TextInput
187
id="collection"
188
name="collection"
189
-
placeholder="Optional (default: record type)"
190
class="w-[15rem]"
191
/>
192
</div>
···
172
></span>
173
<span>{props.create ? "Creating" : "Editing"} record</span>
174
</div>
175
+
<button
176
+
onclick={() => setOpenDialog(false)}
177
+
class="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"
178
+
>
179
+
<span class="iconify lucide--x"></span>
180
</button>
181
</div>
182
<form ref={formRef} class="flex flex-col gap-y-2">
···
189
<TextInput
190
id="collection"
191
name="collection"
192
+
placeholder="Optional (default: $type)"
193
class="w-[15rem]"
194
/>
195
</div>
+52
-6
src/components/search.tsx
+52
-6
src/components/search.tsx
···
2
import { A, useLocation, useNavigate } from "@solidjs/router";
3
import { createResource, createSignal, For, onCleanup, onMount, Show } from "solid-js";
4
import { isTouchDevice } from "../layout";
5
-
import { appHandleLink, appList, AppUrl } from "../utils/app-urls";
6
import { createDebouncedValue } from "../utils/hooks/debounced";
7
8
export const [showSearch, setShowSearch] = createSignal(false);
9
···
67
input = input.trim().replace(/^@/, "");
68
if (!input.length) return;
69
setShowSearch(false);
70
-
if (input === "me" && localStorage.getItem("lastSignedIn") !== null) {
71
-
navigate(`/at://${localStorage.getItem("lastSignedIn")}`);
72
-
} else if (search()?.length) {
73
navigate(`/at://${search()![0].did}`);
74
} else if (input.startsWith("https://") || input.startsWith("http://")) {
75
const hostLength = input.indexOf("/", 8);
···
87
} else {
88
navigate(`/at://${input.replace("at://", "")}`);
89
}
90
-
setShowSearch(false);
91
};
92
93
return (
···
116
value={input() ?? ""}
117
onInput={(e) => setInput(e.currentTarget.value)}
118
/>
119
-
<Show when={input()}>
120
<button
121
type="button"
122
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500"
···
146
</div>
147
</Show>
148
</form>
149
);
150
};
151
···
2
import { A, useLocation, useNavigate } from "@solidjs/router";
3
import { createResource, createSignal, For, onCleanup, onMount, Show } from "solid-js";
4
import { isTouchDevice } from "../layout";
5
+
import { appHandleLink, appList, appName, AppUrl } from "../utils/app-urls";
6
import { createDebouncedValue } from "../utils/hooks/debounced";
7
+
import { Modal } from "./modal";
8
9
export const [showSearch, setShowSearch] = createSignal(false);
10
···
68
input = input.trim().replace(/^@/, "");
69
if (!input.length) return;
70
setShowSearch(false);
71
+
if (search()?.length) {
72
navigate(`/at://${search()![0].did}`);
73
} else if (input.startsWith("https://") || input.startsWith("http://")) {
74
const hostLength = input.indexOf("/", 8);
···
86
} else {
87
navigate(`/at://${input.replace("at://", "")}`);
88
}
89
};
90
91
return (
···
114
value={input() ?? ""}
115
onInput={(e) => setInput(e.currentTarget.value)}
116
/>
117
+
<Show when={input()} fallback={ListUrlsTooltip()}>
118
<button
119
type="button"
120
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500"
···
144
</div>
145
</Show>
146
</form>
147
+
);
148
+
};
149
+
150
+
const ListUrlsTooltip = () => {
151
+
const [openList, setOpenList] = createSignal(false);
152
+
153
+
let urls: Record<string, AppUrl[]> = {};
154
+
for (const [appUrl, appView] of Object.entries(appList)) {
155
+
if (!urls[appView]) urls[appView] = [appUrl as AppUrl];
156
+
else urls[appView].push(appUrl as AppUrl);
157
+
}
158
+
159
+
return (
160
+
<>
161
+
<Modal open={openList()} onClose={() => setOpenList(false)}>
162
+
<div class="dark:bg-dark-300 dark:shadow-dark-800 absolute top-16 left-[50%] w-[26rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0">
163
+
<div class="mb-2 flex items-center gap-1 font-semibold">
164
+
<span class="iconify lucide--link"></span>
165
+
<span>Supported URLs</span>
166
+
</div>
167
+
<div class="mb-2 text-sm text-neutral-500 dark:text-neutral-400">
168
+
Links that will be parsed automatically, as long as all the data necessary is on the
169
+
URL.
170
+
</div>
171
+
<div class="flex flex-col gap-2 text-sm">
172
+
<For each={Object.entries(appName)}>
173
+
{([appView, name]) => {
174
+
return (
175
+
<div>
176
+
<p class="font-semibold">{name}</p>
177
+
<div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400">
178
+
<For each={urls[appView]}>{(url) => <span>{url}</span>}</For>
179
+
</div>
180
+
</div>
181
+
);
182
+
}}
183
+
</For>
184
+
</div>
185
+
</div>
186
+
</Modal>
187
+
<button
188
+
type="button"
189
+
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-600 dark:active:bg-neutral-500"
190
+
onClick={() => setOpenList(true)}
191
+
>
192
+
<span class="iconify lucide--help-circle"></span>
193
+
</button>
194
+
</>
195
);
196
};
197
+9
src/utils/app-urls.ts
+9
src/utils/app-urls.ts
···
9
Linkat,
10
}
11
12
+
export const appName = {
13
+
[App.Bluesky]: "Bluesky",
14
+
[App.Tangled]: "Tangled",
15
+
[App.Whitewind]: "Whitewind",
16
+
[App.Frontpage]: "Frontpage",
17
+
[App.Pinksea]: "Pinksea",
18
+
[App.Linkat]: "Linkat",
19
+
};
20
+
21
export const appList: Record<AppUrl, App> = {
22
"localhost:19006": App.Bluesky,
23
"blacksky.community": App.Bluesky,
+1
-1
src/views/collection.tsx
+1
-1
src/views/collection.tsx
+11
-19
src/views/record.tsx
+11
-19
src/views/record.tsx
···
10
import { JSONValue } from "../components/json.jsx";
11
import { agent } from "../components/login.jsx";
12
import { Modal } from "../components/modal.jsx";
13
-
import { pds, setCID } from "../components/navbar.jsx";
14
import Tooltip from "../components/tooltip.jsx";
15
import { setNotif } from "../layout.jsx";
16
import { didDocCache, resolveLexiconAuthority, resolvePDS } from "../utils/api.js";
···
34
let rpc: Client;
35
36
const fetchRecord = async () => {
37
-
setCID(undefined);
38
setValidRecord(undefined);
39
setValidSchema(undefined);
40
setLexiconUri(undefined);
···
52
setNotice(res.data.error);
53
throw new Error(res.data.error);
54
}
55
-
setCID(res.data.cid);
56
setExternalLink(checkUri(res.data.uri, res.data.value));
57
resolveLexicon(params.collection as Nsid);
58
verify(res.data);
···
198
label="Copy record"
199
icon="lucide--copy"
200
/>
201
<Show when={externalLink()}>
202
{(externalLink) => (
203
<NavMenu
···
280
<span
281
class={`iconify ${validSchema() ? "lucide--check text-green-500 dark:text-green-400" : "lucide--x text-red-500 dark:text-red-400"}`}
282
></span>
283
-
</div>
284
-
</Show>
285
-
<Show when={lexiconUri()}>
286
-
<div>
287
-
<div class="flex items-center gap-1">
288
-
<span class="iconify lucide--scroll-text"></span>
289
-
<p class="font-semibold">Lexicon document</p>
290
-
</div>
291
-
<div class="truncate text-xs">
292
-
<A
293
-
href={`/${lexiconUri()}`}
294
-
class="text-blue-400 hover:underline active:underline"
295
-
>
296
-
{lexiconUri()}
297
-
</A>
298
-
</div>
299
</div>
300
</Show>
301
</div>
···
10
import { JSONValue } from "../components/json.jsx";
11
import { agent } from "../components/login.jsx";
12
import { Modal } from "../components/modal.jsx";
13
+
import { pds } from "../components/navbar.jsx";
14
import Tooltip from "../components/tooltip.jsx";
15
import { setNotif } from "../layout.jsx";
16
import { didDocCache, resolveLexiconAuthority, resolvePDS } from "../utils/api.js";
···
34
let rpc: Client;
35
36
const fetchRecord = async () => {
37
setValidRecord(undefined);
38
setValidSchema(undefined);
39
setLexiconUri(undefined);
···
51
setNotice(res.data.error);
52
throw new Error(res.data.error);
53
}
54
setExternalLink(checkUri(res.data.uri, res.data.value));
55
resolveLexicon(params.collection as Nsid);
56
verify(res.data);
···
196
label="Copy record"
197
icon="lucide--copy"
198
/>
199
+
<Show when={record()?.cid}>
200
+
{(cid) => <CopyMenu copyContent={cid()} label="Copy CID" icon="lucide--copy" />}
201
+
</Show>
202
+
<Show when={lexiconUri()}>
203
+
<NavMenu
204
+
href={`/${lexiconUri()}`}
205
+
icon="lucide--scroll-text"
206
+
label="Lexicon schema"
207
+
/>
208
+
</Show>
209
<Show when={externalLink()}>
210
{(externalLink) => (
211
<NavMenu
···
288
<span
289
class={`iconify ${validSchema() ? "lucide--check text-green-500 dark:text-green-400" : "lucide--x text-red-500 dark:text-red-400"}`}
290
></span>
291
</div>
292
</Show>
293
</div>