feat: handle paste and drop for image uploader

This commit is contained in:
DIYgod 2023-08-27 23:21:20 +01:00
parent cf87ea0f4e
commit 4dcebd05ff
No known key found for this signature in database
4 changed files with 107 additions and 37 deletions

View File

@ -309,7 +309,7 @@ const EditorExtraProperties = memo(
<EditorExternalUrl updateValue={updateValue} />
<EditorAutofill updateValue={updateValue} />
<div className="w-[480px]">
<EditorCover updateValue={updateValue} />
<EditorCover updateValue={updateValue} enableGlobalEvents={true} />
</div>
<EditorTitle updateValue={updateValue} />
<EditorExcerpt updateValue={updateValue} />

View File

@ -7,9 +7,11 @@ import { EditorValues } from "~/lib/types"
export default function EditorCover({
updateValue,
prompt,
enableGlobalEvents,
}: {
updateValue: (val: EditorValues) => void
prompt?: string
enableGlobalEvents?: boolean
}) {
const { t } = useTranslation("dashboard")
const value = useEditorState((state) => state.cover)
@ -28,6 +30,7 @@ export default function EditorCover({
})
}}
accept="image/*"
enableGlobalEvents={enableGlobalEvents}
/>
{prompt && <div className="text-xs text-gray-400 mt-1">{prompt}</div>}
</div>

View File

@ -1,4 +1,4 @@
import { useState } from "react"
import { useCallback, useState } from "react"
import { FieldLabel } from "~/components/ui/FieldLabel"
import { ImageUploader } from "~/components/ui/ImageUploader"
@ -17,6 +17,25 @@ export default function EditorImages({
const value = useEditorState((state) => state.images)
const [extraValue, setExtraValue] = useState(undefined)
const handleAddImage = useCallback(
(key?: { address: string; mime_type: string }) => {
if (key) {
const tmpValue = [
...(value || []),
{
address: key.address,
mime_type: key.mime_type,
},
]
updateValue({
images: tmpValue,
})
}
setExtraValue(undefined)
},
[value, updateValue],
)
return (
<div>
<FieldLabel label={t("Images")} />
@ -48,21 +67,8 @@ export default function EditorImages({
withMimeType={true}
value={extraValue}
disablePreview={true}
uploadEnd={(key) => {
if (key) {
const tmpValue = [
...(value || []),
{
address: key.address,
mime_type: key.mime_type,
},
]
updateValue({
images: tmpValue,
})
}
setExtraValue(undefined)
}}
enableGlobalEvents={true}
uploadEnd={handleAddImage}
accept="image/*"
/>
</div>

View File

@ -1,4 +1,10 @@
import React, { ChangeEvent, forwardRef, useEffect, useState } from "react"
import React, {
ChangeEvent,
forwardRef,
useCallback,
useEffect,
useState,
} from "react"
import { XMarkIcon } from "@heroicons/react/20/solid"
@ -24,6 +30,7 @@ export const ImageUploader = forwardRef(function ImageUploader(
hasClose,
accept,
disablePreview,
enableGlobalEvents,
...inputProps
}: {
className?: string
@ -32,6 +39,7 @@ export const ImageUploader = forwardRef(function ImageUploader(
hasClose?: boolean
accept?: string
disablePreview?: boolean
enableGlobalEvents?: boolean
} & (
| {
withMimeType?: false
@ -55,29 +63,82 @@ export const ImageUploader = forwardRef(function ImageUploader(
const [loading, setLoading] = useState(false)
const { t } = useTranslation("common")
const handleChange = async (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files?.[0]) {
if (!disablePreview) {
getBase64(event.target.files[0], (url) => {
setImageUrl(url)
})
}
const handleFile = useCallback(
async (file?: File) => {
if (file) {
if (!disablePreview) {
getBase64(file, (url) => {
setImageUrl(url)
})
}
setLoading(true)
uploadStart?.()
const key = (await uploadFile(event.target.files[0])).key
if (withMimeType) {
uploadEnd?.({
address: key,
mime_type: event.target.files[0].type,
})
} else {
uploadEnd?.(key)
setLoading(true)
uploadStart?.()
const key = (await uploadFile(file)).key
if (withMimeType) {
uploadEnd?.({
address: key,
mime_type: file.type,
})
} else {
uploadEnd?.(key)
}
setLoading(false)
}
setLoading(false)
}
},
[disablePreview, uploadEnd, uploadFile, uploadStart, withMimeType],
)
const handleChange = async (event: ChangeEvent<HTMLInputElement>) => {
handleFile(event.target.files?.[0])
}
const handlePaste = useCallback(
async (event: ClipboardEvent) => {
if (event.clipboardData?.items) {
let items = event.clipboardData.items
let blob = null
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
blob = items[i].getAsFile()
break
}
}
if (blob !== null) {
handleFile(blob)
}
}
},
[handleFile],
)
const handleDrop = useCallback(
(e: DragEvent) => {
e.preventDefault()
let files = e.dataTransfer?.files
if (
files &&
files.length === 1 &&
files[0].type.indexOf("image") !== -1
) {
handleFile(files[0])
}
},
[handleFile],
)
useEffect(() => {
if (enableGlobalEvents) {
document.addEventListener("paste", handlePaste)
document.addEventListener("drop", handleDrop)
return () => {
document.removeEventListener("paste", handlePaste)
document.removeEventListener("drop", handleDrop)
}
}
}, [handleDrop, handlePaste, enableGlobalEvents])
const clear = () => {
setImageUrl(undefined)
uploadEnd?.(undefined)