From 50a376ae6b4b1f5dfc1adba9257a64a107c96c05 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Fri, 12 May 2023 17:03:49 +0700 Subject: [PATCH] update composer --- src/shared/composer/imageUploader.tsx | 69 +++++++++++++------- src/shared/composer/modal.tsx | 14 ++-- src/shared/composer/types/post.tsx | 94 ++++++++++++++++++--------- src/shared/icons/trash.tsx | 12 ++++ 4 files changed, 130 insertions(+), 59 deletions(-) create mode 100644 src/shared/icons/trash.tsx diff --git a/src/shared/composer/imageUploader.tsx b/src/shared/composer/imageUploader.tsx index adf0cb93..98d936c0 100644 --- a/src/shared/composer/imageUploader.tsx +++ b/src/shared/composer/imageUploader.tsx @@ -3,8 +3,9 @@ import PlusCircleIcon from '@shared/icons/plusCircle'; import { createBlobFromFile } from '@utils/createBlobFromFile'; import { open } from '@tauri-apps/api/dialog'; +import { listen } from '@tauri-apps/api/event'; import { Body, fetch } from '@tauri-apps/api/http'; -import { useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { Transforms } from 'slate'; import { useSlateStatic } from 'slate-react'; @@ -13,30 +14,14 @@ export function ImageUploader() { const [loading, setLoading] = useState(false); const insertImage = (editor, url) => { - const text = { text: url }; - const image = { type: 'image', url, children: [text] }; + const image = { type: 'image', url, children: [{ text: url }] }; Transforms.insertNodes(editor, image); }; - const openFileDialog = async () => { - const selected: any = await open({ - multiple: false, - filters: [ - { - name: 'Image', - extensions: ['png', 'jpeg', 'jpg', 'gif'], - }, - ], - }); - if (Array.isArray(selected)) { - // user selected multiple files - } else if (selected === null) { - // user cancelled the selection - } else { - setLoading(true); - - const filename = selected.split('/').pop(); - const file = await createBlobFromFile(selected); + const uploadToVoidCat = useCallback( + async (filepath) => { + const filename = filepath.split('/').pop(); + const file = await createBlobFromFile(filepath); const buf = await file.arrayBuffer(); try { @@ -68,12 +53,52 @@ export function ImageUploader() { console.log('There was an error', error); } } + }, + [editor] + ); + + const openFileDialog = async () => { + const selected: any = await open({ + multiple: false, + filters: [ + { + name: 'Image', + extensions: ['png', 'jpeg', 'jpg', 'gif'], + }, + ], + }); + if (Array.isArray(selected)) { + // user selected multiple files + } else if (selected === null) { + // user cancelled the selection + } else { + setLoading(true); + // upload file + uploadToVoidCat(selected); } }; + useEffect(() => { + async function initFileDrop() { + const unlisten = await listen('tauri://file-drop', (event) => { + // set loading state + setLoading(true); + // upload file + uploadToVoidCat(event.payload[0]); + }); + + return () => { + unlisten(); + }; + } + + initFileDrop(); + }, [uploadToVoidCat]); + return ( +
diff --git a/src/shared/composer/types/post.tsx b/src/shared/composer/types/post.tsx index 8239df72..82e3b6a9 100644 --- a/src/shared/composer/types/post.tsx +++ b/src/shared/composer/types/post.tsx @@ -1,4 +1,5 @@ import { ImageUploader } from '@shared/composer/imageUploader'; +import TrashIcon from '@shared/icons/trash'; import { RelayContext } from '@shared/relayProvider'; import { WRITEONLY_RELAYS } from '@stores/constants'; @@ -7,29 +8,65 @@ import { dateToUnix } from '@utils/date'; import { getEventHash, signEvent } from 'nostr-tools'; import { useCallback, useContext, useMemo, useState } from 'react'; -import { Node, createEditor } from 'slate'; +import { Node, Transforms, createEditor } from 'slate'; import { withHistory } from 'slate-history'; -import { Editable, Slate, withReact } from 'slate-react'; +import { Editable, ReactEditor, Slate, useSlateStatic, withReact } from 'slate-react'; -const initialValue = [ - { - type: 'paragraph', - children: [{ text: '' }], - }, -]; +const withImages = (editor) => { + const { isVoid } = editor; + + editor.isVoid = (element) => { + return element.type === 'image' ? true : isVoid(element); + }; + + return editor; +}; + +const ImagePreview = ({ attributes, children, element }: { attributes: any; children: any; element: any }) => { + const editor: any = useSlateStatic(); + const path = ReactEditor.findPath(editor, element); + + return ( +
+ {children} +
+ + +
+
+ ); +}; export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) { const pool: any = useContext(RelayContext); - const editor = useMemo(() => withHistory(withReact(createEditor())), []); - const [content, setContent] = useState(null); + + const editor = useMemo(() => withReact(withImages(withHistory(createEditor()))), []); + const [content, setContent] = useState([ + { + children: [ + { + text: '', + }, + ], + }, + ]); const serialize = useCallback((nodes: Node[]) => { return nodes.map((n) => Node.string(n)).join('\n'); }, []); const submit = () => { + // serialize content + const serializedContent = serialize(content); + console.log(serializedContent); + const event: any = { - content: content, + content: serializedContent, created_at: dateToUnix(), kind: 1, pubkey: pubkey, @@ -40,35 +77,33 @@ export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) { // publish note pool.publish(event, WRITEONLY_RELAYS); - // reset form - setContent(''); }; - return ( - { - const isAstChange = editor.operations.some((op) => 'set_selection' !== op.type); - if (isAstChange) { - const content = serialize(value); - setContent(content); + const renderElement = useCallback((props: any) => { + switch (props.element.type) { + case 'image': + if (props.element.url) { + return ; } - }} - > + default: + return

{props.children}

; + } + }, []); + + return ( +
-
+
@@ -76,6 +111,7 @@ export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) {