add kind of hacky image upload

This commit is contained in:
hzrd149
2023-03-09 17:23:41 -06:00
parent e1e970b152
commit 8e88656f7e
3 changed files with 100 additions and 5 deletions

View File

@@ -215,3 +215,15 @@ export const UnlockIcon = createIcon({
d: "M7 10h13a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V11a1 1 0 0 1 1-1h1V9a7 7 0 0 1 13.262-3.131l-1.789.894A5 5 0 0 0 7 9v1zm-2 2v8h14v-8H5zm5 3h4v2h-4v-2z",
defaultProps,
});
export const ImageIcon = createIcon({
displayName: "ImageIcon",
d: "M4.828 21l-.02.02-.021-.02H2.992A.993.993 0 0 1 2 20.007V3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H4.828zM20 15V5H4v14L14 9l6 6zm0 2.828l-6-6L6.828 19H20v-1.172zM8 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z",
defaultProps,
});
export const CameraIcon = createIcon({
displayName: "CameraIcon",
d: "M9.828 5l-2 2H4v12h16V7h-3.828l-2-2H9.828zM9 3h6l2 2h4a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h4l2-2zm3 15a5.5 5.5 0 1 1 0-11 5.5 5.5 0 0 1 0 11zm0-2a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z",
defaultProps,
});

View File

@@ -67,7 +67,11 @@ export const Note = React.memo(({ event, maxHeight }: NoteProps) => {
</Flex>
</CardHeader>
<CardBody px="2" py="0">
<NoteContents event={event} trusted={following.includes(event.pubkey)} maxHeight={maxHeight} />
<NoteContents
event={event}
trusted={event.pubkey === account.pubkey || following.includes(event.pubkey)}
maxHeight={maxHeight}
/>
</CardBody>
<CardFooter padding="2" display="flex" gap="2">
<IconButton

View File

@@ -3,15 +3,17 @@ import {
ModalOverlay,
ModalContent,
ModalBody,
ModalFooter,
Flex,
Button,
Textarea,
Text,
useDisclosure,
VisuallyHiddenInput,
IconButton,
useToast,
} from "@chakra-ui/react";
import moment from "moment";
import React, { useState } from "react";
import React, { useRef, useState } from "react";
import { useList } from "react-use";
import { nostrPostAction, PostResult } from "../../classes/nostr-post-action";
import { getReferences } from "../../helpers/nostr-event";
@@ -19,6 +21,7 @@ import { useWriteRelayUrls } from "../../hooks/use-client-relays";
import { useIsMobile } from "../../hooks/use-is-mobile";
import { useSigningContext } from "../../providers/signing-provider";
import { DraftNostrEvent, NostrEvent } from "../../types/nostr-event";
import { CameraIcon, ImageIcon } from "../icons";
import { NoteLink } from "../note-link";
import { NoteContents } from "../note/note-contents";
import { PostResults } from "./post-results";
@@ -39,6 +42,8 @@ type PostModalProps = {
};
export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) => {
const isMobile = useIsMobile();
const toast = useToast();
const { requestSignature } = useSigningContext();
const writeRelays = useWriteRelayUrls();
const [waiting, setWaiting] = useState(false);
@@ -46,6 +51,33 @@ export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) =>
const [results, resultsActions] = useList<PostResult>();
const { isOpen: showPreview, onToggle: togglePreview } = useDisclosure();
const [draft, setDraft] = useState<DraftNostrEvent>(() => Object.assign(emptyDraft(), initialDraft));
const imageUploadRef = useRef<HTMLInputElement | null>(null);
const imageCaptureRef = useRef<HTMLInputElement | null>(null);
const [uploading, setUploading] = useState(false);
const uploadImage = async (imageFile: File) => {
try {
if (!imageFile.type.includes("image")) throw new Error("Only images are supported");
setUploading(true);
const payload = new FormData();
payload.append("fileToUpload", imageFile);
const response = await fetch("https://nostr.build/upload.php", { body: payload, method: "POST" }).then((res) =>
res.text()
);
const imageUrl = response.match(/https:\/\/nostr\.build\/i\/[\w.]+/)?.[0];
if (imageUrl) {
setDraft((d) => ({ ...d, content: (d.content += imageUrl) }));
}
} catch (e) {
if (e instanceof Error) {
toast({
status: "error",
description: e.message,
});
}
}
setUploading(false);
};
const handleContentChange: React.ChangeEventHandler<HTMLTextAreaElement> = (event) => {
setDraft((d) => ({ ...d, content: event.target.value }));
@@ -87,9 +119,56 @@ export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) =>
{showPreview ? (
<NoteContents event={draft} trusted />
) : (
<Textarea autoFocus mb="2" value={draft.content} onChange={handleContentChange} rows={5} />
<Textarea
autoFocus
mb="2"
value={draft.content}
onChange={handleContentChange}
rows={5}
onPaste={(e) => {
const imageFile = Array.from(e.clipboardData.files).find((f) => f.type.includes("image"));
if (imageFile) uploadImage(imageFile);
}}
/>
)}
<Flex gap="2" alignItems="center" justifyContent="flex-end">
<Flex mr="auto" gap="2">
<VisuallyHiddenInput
type="file"
accept="image/*"
ref={imageUploadRef}
onChange={(e) => {
const img = e.target.files?.[0];
if (img) uploadImage(img);
}}
/>
<VisuallyHiddenInput
type="file"
accept="image/*"
ref={imageCaptureRef}
capture="environment"
onChange={(e) => {
const img = e.target.files?.[0];
if (img) uploadImage(img);
}}
/>
<IconButton
icon={<ImageIcon />}
aria-label="Upload Image"
title="Upload Image"
onClick={() => imageUploadRef.current?.click()}
isLoading={uploading}
/>
{isMobile && (
<IconButton
icon={<CameraIcon />}
aria-label="Capture Image"
title="Capture Image"
onClick={() => imageUploadRef.current?.click()}
isLoading={uploading}
/>
)}
</Flex>
{draft.content.length > 0 && <Button onClick={togglePreview}>Preview</Button>}
<Button onClick={onClose}>Cancel</Button>
<Button colorScheme="blue" type="submit" isLoading={waiting} onClick={handleSubmit} isDisabled={!canSubmit}>
@@ -104,7 +183,7 @@ export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) =>
<Modal isOpen={isOpen} onClose={onClose} size="4xl">
<ModalOverlay />
<ModalContent>
<ModalBody padding="4">{renderContent()}</ModalBody>
<ModalBody padding={isMobile ? "2" : "4"}>{renderContent()}</ModalBody>
</ModalContent>
</Modal>
);