feat: handle paste and drop for image uploader
This commit is contained in:
parent
cf87ea0f4e
commit
4dcebd05ff
|
|
@ -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} />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue