atproto explorer pdsls.dev
atproto tool

add create/edit/delete notif

Changed files
+35 -22
src
+3
src/components/create.tsx
···
import { TextInput } from "./text-input.jsx";
import { Modal } from "./modal.jsx";
import { Button } from "./button.jsx";
+
import { setNotif } from "../layout.jsx";
export const RecordEditor = (props: { create: boolean; record?: any; refetch?: any }) => {
const navigate = useNavigate();
···
return;
}
setOpenDialog(false);
+
setNotif({ show: true, icon: "lucide--file-check", text: "Record created" });
navigate(`/${res.data.uri}`);
};
···
}
}
setOpenDialog(false);
+
setNotif({ show: true, icon: "lucide--file-check", text: "Record edited" });
props.refetch();
} catch (err: any) {
setNotice(err.message);
+18 -5
src/layout.tsx
···
-
import { createEffect, ErrorBoundary, Show, Suspense } from "solid-js";
+
import { createEffect, createSignal, ErrorBoundary, Show, Suspense } from "solid-js";
import { A, RouteSectionProps, useLocation, useNavigate, useParams } from "@solidjs/router";
import { agent } from "./components/login.jsx";
import { RecordEditor } from "./components/create.jsx";
···
import { Meta, MetaProvider } from "@solidjs/meta";
import { Settings } from "./components/settings.jsx";
import { Handle } from "@atcute/lexicons";
-
import { copyNotice } from "./utils/copy.js";
+
+
export const [notif, setNotif] = createSignal<{
+
show: boolean;
+
icon?: string;
+
text?: string;
+
}>({ show: false });
const Layout = (props: RouteSectionProps<unknown>) => {
const params = useParams();
const location = useLocation();
const navigate = useNavigate();
+
let timeout: number;
createEffect(async () => {
if (params.repo && !params.repo.startsWith("did:")) {
const did = await resolveHandle(params.repo as Handle);
navigate(location.pathname.replace(params.repo, did));
+
}
+
});
+
+
createEffect(() => {
+
if (notif().show) {
+
clearTimeout(timeout);
+
timeout = setTimeout(() => setNotif({ show: false }), 3000);
}
});
···
</ErrorBoundary>
</Show>
</div>
-
<Show when={copyNotice()}>
+
<Show when={notif().show}>
<div class="dark:shadow-dark-900/80 dark:bg-dark-100/70 fixed bottom-10 z-50 flex items-center rounded-lg border-[0.5px] border-neutral-300 bg-neutral-100/70 p-2 shadow-md backdrop-blur-xs dark:border-neutral-700">
-
<span class="iconify lucide--clipboard-check mr-1"></span>
-
Copied to clipboard
+
<span class={`iconify ${notif().icon} mr-1`}></span>
+
{notif().text}
</div>
</Show>
</div>
+2 -8
src/utils/copy.ts
···
-
import { createSignal } from "solid-js";
-
-
export const [copyNotice, setCopyNotice] = createSignal(false);
-
-
let timeout: number;
+
import { setNotif } from "../layout";
export const addToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
-
setCopyNotice(true);
-
clearTimeout(timeout);
-
timeout = setTimeout(() => setCopyNotice(false), 3000);
+
setNotif({ show: true, icon: "lucide--clipboard-check", text: "Copied to clipboard" });
};
+10 -9
src/views/collection.tsx
···
import { ComAtprotoRepoApplyWrites, ComAtprotoRepoGetRecord } from "@atcute/atproto";
import { TextInput } from "../components/text-input.jsx";
import { Button } from "../components/button.jsx";
+
import { setNotif } from "../layout.jsx";
interface AtprotoRecord {
rkey: string;
···
const [response, { refetch }] = createResource(fetchRecords);
const deleteRecords = async () => {
-
const writes = records
-
.filter((record) => record.toDelete)
-
.map((record): $type.enforce<ComAtprotoRepoApplyWrites.Delete> => {
-
return {
-
$type: "com.atproto.repo.applyWrites#delete",
-
collection: params.collection as `${string}.${string}.${string}`,
-
rkey: record.rkey,
-
};
-
});
+
const recsToDel = records.filter((record) => record.toDelete);
+
const writes = recsToDel.map((record): $type.enforce<ComAtprotoRepoApplyWrites.Delete> => {
+
return {
+
$type: "com.atproto.repo.applyWrites#delete",
+
collection: params.collection as `${string}.${string}.${string}`,
+
rkey: record.rkey,
+
};
+
});
const BATCHSIZE = 200;
rpc = new Client({ handler: agent()! });
···
},
});
}
+
setNotif({ show: true, icon: "lucide--trash-2", text: `${recsToDel.length} records deleted` });
setBatchDelete(false);
setRecords([]);
setCursor(undefined);
+2
src/views/record.tsx
···
import Tooltip from "../components/tooltip.jsx";
import { Modal } from "../components/modal.jsx";
import { Button } from "../components/button.jsx";
+
import { setNotif } from "../layout.jsx";
export const RecordView = () => {
const navigate = useNavigate();
···
rkey: params.rkey,
},
});
+
setNotif({ show: true, icon: "lucide--trash-2", text: "Record deleted" });
navigate(`/at://${params.repo}/${params.collection}`);
};