import { Dialog, Transition } from "@headlessui/react"; import { createBlock } from "@libs/storage"; import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { CancelIcon, CommandIcon } from "@shared/icons"; import { Image } from "@shared/image"; import { RelayContext } from "@shared/relayProvider"; import { DEFAULT_AVATAR } from "@stores/constants"; import { ADD_IMAGEBLOCK_SHORTCUT } from "@stores/shortcuts"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { open } from "@tauri-apps/api/dialog"; import { Body, fetch } from "@tauri-apps/api/http"; import { createBlobFromFile } from "@utils/createBlobFromFile"; import { dateToUnix } from "@utils/date"; import { useAccount } from "@utils/hooks/useAccount"; import { Fragment, useContext, useEffect, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { useHotkeys } from "react-hotkeys-hook"; export function AddImageBlock() { const ndk = useContext(RelayContext); const queryClient = useQueryClient(); const [loading, setLoading] = useState(false); const [isOpen, setIsOpen] = useState(false); const [image, setImage] = useState(""); const { account } = useAccount(); const tags = useRef(null); const openModal = () => { setIsOpen(true); }; const closeModal = () => { setIsOpen(false); }; useHotkeys(ADD_IMAGEBLOCK_SHORTCUT, () => openModal()); const { register, handleSubmit, reset, setValue, formState: { isDirty, isValid }, } = useForm(); const openFileDialog = async () => { const selected: any = await open({ multiple: false, filters: [ { name: "Image", extensions: ["png", "jpeg", "jpg"], }, ], }); if (Array.isArray(selected)) { // user selected multiple files } else if (selected === null) { // user cancelled the selection } else { const filename = selected.split("/").pop(); const file = await createBlobFromFile(selected); const buf = await file.arrayBuffer(); const res: any = await fetch("https://void.cat/upload?cli=false", { method: "POST", timeout: 5, headers: { accept: "*/*", "Content-Type": "application/octet-stream", "V-Filename": filename, "V-Description": "Upload from https://lume.nu", "V-Strip-Metadata": "true", }, body: Body.bytes(buf), }); if (res.ok) { const imageURL = `https://void.cat/d/${res.data.file.id}.webp`; tags.current = [ ["url", imageURL], ["m", res.data.file.metadata.mimeType], ["x", res.data.file.metadata.digest], ["size", res.data.file.metadata.size], ["magnet", res.data.file.metadata.magnetLink], ]; setImage(imageURL); } } }; const block = useMutation({ mutationFn: (data: any) => { return createBlock(data.kind, data.title, data.content); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["blocks"] }); }, }); const onSubmit = (data: any) => { setLoading(true); const signer = new NDKPrivateKeySigner(account.privkey); ndk.signer = signer; const event = new NDKEvent(ndk); // build event event.content = data.title; event.kind = 1063; event.created_at = dateToUnix(); event.pubkey = account.pubkey; event.tags = tags.current; // publish event event.publish(); // mutate block.mutate({ kind: 0, title: data.title, content: data.content }); setLoading(false); // reset form reset(); // close modal closeModal(); }; useEffect(() => { setValue("content", image); }, [setValue, image]); return ( <>
Create image block
Pin your favorite image to Space then you can view every time that you use Lume, your image will be broadcast to Nostr Relay as well
content
); }