mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-02 16:38:14 +00:00
Tabs Improvements: - refactor tabs so no more race condition revolving unneccessary signals - clean up signals - refactor upload modal movement to be non-signaled and generalized for more files types - better naming for files and components, better error handling, eslint type any fix - upload file screen can use less state rerenders and better error messages Object Uploader - adapt the old object upload modal with 3d object preview into the updated best version of upload modal - preview loader code improvements, better flow and organization Sets Tab: - create a set tab, it currently show objects - hide it behind a FeatureFlag --------- Co-authored-by: wil <wil@storyteller.ai>
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import React, { ReactNode, useId, useRef, useState } from "react";
|
|
import { AssetType } from "~/enums";
|
|
import { UploadModalObject } from "~/components";
|
|
import { twMerge } from "tailwind-merge";
|
|
|
|
interface Props {
|
|
render: (parentId: string) => ReactNode;
|
|
fileTypes?: string[];
|
|
onChange?: (file?: React.ChangeEvent) => void;
|
|
onSuccess: () => void;
|
|
panelClass?: string;
|
|
type: AssetType;
|
|
}
|
|
|
|
export function FileWrapper({
|
|
render,
|
|
fileTypes = [],
|
|
onSuccess,
|
|
type,
|
|
...rest
|
|
}: Props) {
|
|
const fileRef = useRef<HTMLInputElement>(null);
|
|
const [file, setFile] = useState<File | undefined>();
|
|
const [modalOpen, setModalOpen] = useState(false);
|
|
const [resetModal, setResetModal] = useState(false);
|
|
const [dragging, setDragging] = useState(false);
|
|
const id = "file-input-" + useId();
|
|
const accept = fileTypes
|
|
.map((fileType) => `.${fileType.toLowerCase()}`)
|
|
.join(",");
|
|
|
|
const clearFile = () => {
|
|
if (fileRef.current !== null) {
|
|
fileRef.current.value = "";
|
|
setFile(undefined);
|
|
}
|
|
};
|
|
const closeModal = () => setModalOpen(false);
|
|
|
|
const fileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
setResetModal(true);
|
|
event.preventDefault();
|
|
setFile(event.target?.files?.[0]);
|
|
setModalOpen(true);
|
|
};
|
|
const onDragDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
};
|
|
const onDragEvent =
|
|
(onOff: boolean) =>
|
|
(event: React.DragEvent<HTMLDivElement>): void => {
|
|
setDragging(onOff);
|
|
onDragDrop(event);
|
|
};
|
|
const onDrop = (event: React.DragEvent<HTMLDivElement>): void => {
|
|
setDragging(false);
|
|
onDragDrop(event);
|
|
if (event.dataTransfer.files && event.dataTransfer.files[0]) {
|
|
setResetModal(true);
|
|
setFile(event.dataTransfer.files[0]);
|
|
setModalOpen(true);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={twMerge(
|
|
"flex h-full flex-col gap-3.5 overflow-y-auto",
|
|
dragging ? "border-white/33 border bg-ui-controls-button" : "",
|
|
)}
|
|
onDragLeave={onDragEvent(false)}
|
|
onDragOver={onDragEvent(true)}
|
|
onDrop={onDrop}
|
|
>
|
|
<input
|
|
accept={accept}
|
|
className="absolute hidden h-0 w-0"
|
|
onChange={fileChange}
|
|
type="file"
|
|
id={id}
|
|
ref={fileRef}
|
|
{...rest}
|
|
/>
|
|
{render(id)}
|
|
<UploadModalObject
|
|
closeModal={closeModal}
|
|
file={file!}
|
|
isOpen={modalOpen}
|
|
onClose={clearFile}
|
|
onSuccess={onSuccess}
|
|
resetModal={resetModal}
|
|
setResetModal={setResetModal}
|
|
type={type}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|