mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-28 02:34:42 +01:00
149 lines
4.9 KiB
TypeScript
149 lines
4.9 KiB
TypeScript
import Uploady, { useRequestPreSend, UPLOADER_EVENTS } from "@rpldy/uploady";
|
|
import { asUploadButton } from "@rpldy/upload-button";
|
|
// import { fetchUploadUrl } from "./fetch-upload-img-url";
|
|
import ImagePreviews from "./ImagePreviews";
|
|
import UploadDropZone from "@rpldy/upload-drop-zone";
|
|
import { forwardRef, useCallback, useState } from "react";
|
|
import styles from './styles.module.scss'
|
|
import { AiOutlineCloudUpload } from "react-icons/ai";
|
|
import { motion } from "framer-motion";
|
|
import { getMockSenderEnhancer } from "@rpldy/mock-sender";
|
|
import ScreenshotThumbnail from "./ScreenshotThumbnail";
|
|
import { FiCamera } from "react-icons/fi";
|
|
import { Control, Path, useController } from "react-hook-form";
|
|
import { ImageInput } from "src/graphql";
|
|
import { fetchUploadImageUrl } from "src/api/uploading";
|
|
|
|
|
|
|
|
const mockSenderEnhancer = getMockSenderEnhancer({
|
|
delay: 1500,
|
|
});
|
|
|
|
const MAX_UPLOAD_COUNT = 4 as const;
|
|
|
|
|
|
interface Props {
|
|
value: ImageInput[],
|
|
onChange: (new_value: ImageInput[]) => void
|
|
}
|
|
|
|
|
|
export default function ScreenshotsInput(props: Props) {
|
|
|
|
const { value: uploadedFiles, onChange } = props;
|
|
|
|
|
|
const [uploadingCount, setUploadingCount] = useState(0)
|
|
|
|
|
|
const canUploadMore = uploadingCount + uploadedFiles.length < MAX_UPLOAD_COUNT;
|
|
const placeholdersCount = (MAX_UPLOAD_COUNT - (uploadingCount + uploadedFiles.length + 1));
|
|
|
|
|
|
return (
|
|
<Uploady
|
|
multiple={true}
|
|
inputFieldName='file'
|
|
grouped={false}
|
|
listeners={{
|
|
[UPLOADER_EVENTS.BATCH_ADD]: (batch) => {
|
|
setUploadingCount(v => v + batch.items.length)
|
|
},
|
|
[UPLOADER_EVENTS.ITEM_FINALIZE]: () => setUploadingCount(v => v - 1),
|
|
[UPLOADER_EVENTS.ITEM_FINISH]: (item) => {
|
|
|
|
// Just for mocking purposes
|
|
const dataUrl = URL.createObjectURL(item.file);
|
|
|
|
const { id, filename, variants } = item?.uploadResponse?.data?.result ?? {
|
|
id: Math.random().toString(),
|
|
filename: item.file.name,
|
|
variants: [
|
|
"",
|
|
dataUrl
|
|
]
|
|
}
|
|
if (id) {
|
|
onChange([...uploadedFiles, { id, name: filename, url: variants[1] }].slice(-MAX_UPLOAD_COUNT))
|
|
}
|
|
}
|
|
}}
|
|
>
|
|
|
|
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-16 mt-24">
|
|
{canUploadMore && <DropZoneButton />}
|
|
{uploadedFiles.map(f => <ScreenshotThumbnail
|
|
key={f.id}
|
|
url={f.url}
|
|
onCancel={() => {
|
|
onChange(uploadedFiles.filter(file => file.id !== f.id))
|
|
}} />)}
|
|
<ImagePreviews />
|
|
{(placeholdersCount > 0) &&
|
|
Array(placeholdersCount).fill(0).map((_, idx) => <ScreenshotThumbnail key={idx} />)}
|
|
</div>
|
|
</Uploady>
|
|
)
|
|
}
|
|
|
|
const DropZone = forwardRef<any, any>((props, ref) => {
|
|
const { onClick, ...buttonProps } = props;
|
|
|
|
|
|
useRequestPreSend(async (data) => {
|
|
const filename = data.items?.[0].file.name ?? ''
|
|
|
|
const res = await fetchUploadImageUrl({ filename });
|
|
|
|
return {
|
|
options: {
|
|
destination: {
|
|
url: res.uploadURL
|
|
},
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
const onZoneClick = useCallback(
|
|
(e: any) => {
|
|
if (onClick) {
|
|
onClick(e);
|
|
}
|
|
},
|
|
[onClick]
|
|
);
|
|
|
|
return <UploadDropZone
|
|
{...buttonProps}
|
|
ref={ref}
|
|
onDragOverClassName={styles.active}
|
|
extraProps={{ onClick: onZoneClick }}
|
|
className={`${styles.zone} aspect-video relative rounded-16 md:rounded-14 overflow-hidden border-2 border-gray-200 flex flex-col justify-center items-center cursor-pointer border-dashed`}
|
|
>
|
|
<div className={styles.idle_content}>
|
|
<p className="text-center text-gray-400 text-body1 mb-8"><FiCamera /></p>
|
|
<div className={`text-gray-600 text-center text-body4`}>
|
|
<span className="text-blue-500 underline">Browse images</span> or <br /> <span className="text-blue-500">drop </span>
|
|
them here
|
|
</div>
|
|
</div>
|
|
|
|
<motion.div
|
|
animate={{
|
|
y: 5,
|
|
}}
|
|
transition={{
|
|
duration: .5,
|
|
repeat: Infinity,
|
|
repeatType: 'mirror'
|
|
}}
|
|
className={`${styles.active_content} text-white font-bold text-center`}>
|
|
Drop to upload <br /> <AiOutlineCloudUpload className="scale-150 text-body1 mt-16" />
|
|
</motion.div>
|
|
</UploadDropZone>
|
|
})
|
|
|
|
const DropZoneButton = asUploadButton(DropZone);
|