From dffe300a5ff84e63f72bc7e11017c6de7655eaa5 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:23:50 +0700 Subject: [PATCH] add create space --- src/app/space/components/add.tsx | 67 ++++++ src/app/space/components/addFeed.tsx | 179 ++++++++++++++ src/app/space/components/addImage.tsx | 265 +++++++++++++++++++++ src/app/space/components/create.tsx | 216 ----------------- src/app/space/components/imageUploader.tsx | 86 ------- src/app/space/pages/index.page.tsx | 8 +- src/shared/icons/feed.tsx | 24 ++ src/shared/icons/image.tsx | 21 ++ src/shared/icons/index.tsx | 2 + 9 files changed, 562 insertions(+), 306 deletions(-) create mode 100644 src/app/space/components/add.tsx create mode 100644 src/app/space/components/addFeed.tsx create mode 100644 src/app/space/components/addImage.tsx delete mode 100644 src/app/space/components/create.tsx delete mode 100644 src/app/space/components/imageUploader.tsx create mode 100644 src/shared/icons/feed.tsx create mode 100644 src/shared/icons/image.tsx diff --git a/src/app/space/components/add.tsx b/src/app/space/components/add.tsx new file mode 100644 index 00000000..5d2c4934 --- /dev/null +++ b/src/app/space/components/add.tsx @@ -0,0 +1,67 @@ +import { AddFeedBlock } from "@app/space/components/addFeed"; +import { AddImageBlock } from "@app/space/components/addImage"; +import { Menu, Transition } from "@headlessui/react"; +import { FeedIcon, ImageIcon, PlusIcon } from "@shared/icons"; +import { Fragment, useState } from "react"; + +export function AddBlock() { + const [imageModal, setImageModal] = useState(false); + const [feedModal, setFeedModal] = useState(false); + + const openAddImageModal = () => { + setImageModal(true); + }; + + const openAddFeedModal = () => { + setFeedModal(true); + }; + + return ( + <> + + +
+ +
+
+ + +
+ + + + + + +
+
+
+
+ + {imageModal && } + {feedModal && } + + ); +} diff --git a/src/app/space/components/addFeed.tsx b/src/app/space/components/addFeed.tsx new file mode 100644 index 00000000..2ebefa83 --- /dev/null +++ b/src/app/space/components/addFeed.tsx @@ -0,0 +1,179 @@ +import { Dialog, Transition } from "@headlessui/react"; +import { CancelIcon } from "@shared/icons"; +import { useActiveAccount } from "@stores/accounts"; +import { createBlock } from "@utils/storage"; +import { nip19 } from "nostr-tools"; +import { Fragment, useState } from "react"; +import { useForm } from "react-hook-form"; + +export function AddFeedBlock({ parentState }: { parentState: any }) { + const account = useActiveAccount((state: any) => state.account); + + const [loading, setLoading] = useState(false); + const [isOpen, setIsOpen] = useState(true); + + const closeModal = () => { + // update local state + setIsOpen(false); + // update parent state + parentState(false); + }; + + const { + register, + handleSubmit, + reset, + formState: { isDirty, isValid }, + } = useForm(); + + const onSubmit = (data: any) => { + setLoading(true); + + let pubkey = data.content; + + if (pubkey.substring(0, 4) === "npub") { + pubkey = nip19.decode(pubkey).data; + } + + // insert to database + createBlock(account.id, 1, data.title, pubkey); + + setTimeout(() => { + setLoading(false); + // reset form + reset(); + // close modal + closeModal(); + }, 1000); + }; + + 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 + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+
+
+
+ ); +} diff --git a/src/app/space/components/addImage.tsx b/src/app/space/components/addImage.tsx new file mode 100644 index 00000000..954cd0ce --- /dev/null +++ b/src/app/space/components/addImage.tsx @@ -0,0 +1,265 @@ +import { Dialog, Transition } from "@headlessui/react"; +import { CancelIcon, ImageIcon } from "@shared/icons"; +import { Image } from "@shared/image"; +import { RelayContext } from "@shared/relayProvider"; +import { useActiveAccount } from "@stores/accounts"; +import { WRITEONLY_RELAYS } from "@stores/constants"; +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 { createBlock } from "@utils/storage"; +import { getEventHash, getSignature } from "nostr-tools"; +import { Fragment, useContext, useEffect, useRef, useState } from "react"; +import { useForm } from "react-hook-form"; + +export function AddImageBlock({ parentState }: { parentState: any }) { + const pool: any = useContext(RelayContext); + const account = useActiveAccount((state: any) => state.account); + + const [loading, setLoading] = useState(false); + const [isOpen, setIsOpen] = useState(true); + const [image, setImage] = useState(""); + + const tags = useRef(null); + + const closeModal = () => { + // update local state + setIsOpen(false); + // update parent state + parentState(false); + }; + + 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 onSubmit = (data: any) => { + setLoading(true); + + const event: any = { + content: data.title, + created_at: dateToUnix(), + kind: 1063, + pubkey: account.pubkey, + tags: tags.current, + }; + + console.log(event); + + event.id = getEventHash(event); + event.sig = getSignature(event, account.privkey); + + // publish channel + pool.publish(event, WRITEONLY_RELAYS); + + // insert to database + createBlock(account.id, 0, data.title, data.content); + + setTimeout(() => { + setLoading(false); + // reset form + reset(); + // close modal + closeModal(); + }, 1000); + }; + + 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 +
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ ); +} diff --git a/src/app/space/components/create.tsx b/src/app/space/components/create.tsx deleted file mode 100644 index 8f231781..00000000 --- a/src/app/space/components/create.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { BlockImageUploader } from "./imageUploader"; -import { Dialog, Transition } from "@headlessui/react"; -import { CancelIcon, PlusIcon } from "@shared/icons"; -import { Image } from "@shared/image"; -import { useActiveAccount } from "@stores/accounts"; -import { DEFAULT_AVATAR } from "@stores/constants"; -import { createBlock } from "@utils/storage"; -import { Fragment, useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; - -export function CreateBlockModal() { - const account = useActiveAccount((state: any) => state.account); - const { register, handleSubmit, reset, watch, setValue } = useForm(); - - const [image, setImage] = useState(DEFAULT_AVATAR); - const [isOpen, setIsOpen] = useState(false); - const [loading, setLoading] = useState(false); - - const kind = watch("kind"); - - const closeModal = () => { - setIsOpen(false); - }; - - const openModal = () => { - setIsOpen(true); - }; - - const onSubmit = (data: any) => { - setLoading(true); - - createBlock(account.id, data.kind, data.title, data.content).then(() => { - // reset form - reset(); - // close modal - setIsOpen(false); - // stop loading - setLoading(false); - }); - }; - - useEffect(() => { - setValue("content", image); - }, [setValue, image]); - - return ( - <> - - - - -
- -
- - -
-
-
- - Create block - - -
- - Personalize your space by adding a new block. - -
-
-
-
-
- -
- -
-
-
- -
- -
-
-
- - {kind === "1" ? ( -
-