Add Media.Dropzone and Media.Preview as isolated elements

Introduce `Media.*` to modularize and customize file upload handling. Refactor media-related components to improve usability, add max item limits, overwrite support, and event callbacks.
This commit is contained in:
dswbx
2025-01-09 15:43:43 +01:00
parent 5c7bfeab8f
commit d182640981
11 changed files with 358 additions and 127 deletions

View File

@@ -11,6 +11,7 @@ import FlowFormTest from "../../routes/test/tests/flow-form-test";
import ModalTest from "../../routes/test/tests/modal-test";
import QueryJsonFormTest from "../../routes/test/tests/query-jsonform";
import DropdownTest from "./tests/dropdown-test";
import DropzoneElementTest from "./tests/dropzone-element-test";
import EntityFieldsForm from "./tests/entity-fields-form";
import FlowsTest from "./tests/flows-test";
import JsonFormTest from "./tests/jsonform-test";
@@ -41,7 +42,8 @@ const tests = {
AppShellAccordionsTest,
SwaggerTest,
SWRAndAPI,
SwrAndDataApi
SwrAndDataApi,
DropzoneElementTest
} as const;
export default function TestRoutes() {

View File

@@ -0,0 +1,78 @@
import { type DropzoneRenderProps, Media } from "ui/elements";
import { Scrollable } from "ui/layouts/AppShell/AppShell";
export default function DropzoneElementTest() {
return (
<Scrollable>
<div className="flex flex-col w-full h-full p-4 gap-4">
<div>
<b>Dropzone User Avatar 1 (fully customized)</b>
<Media.Dropzone
entity={{ name: "users", id: 1, field: "avatar" }}
maxItems={1}
overwrite
>
{(props) => <CustomUserAvatarDropzone {...props} />}
</Media.Dropzone>
</div>
<div>
<b>Dropzone User Avatar 1 (overwrite)</b>
<Media.Dropzone
entity={{ name: "users", id: 1, field: "avatar" }}
maxItems={1}
overwrite
/>
</div>
<div>
<b>Dropzone User Avatar 1</b>
<Media.Dropzone entity={{ name: "users", id: 1, field: "avatar" }} maxItems={1} />
</div>
<div>
<b>Dropzone Container blank w/ query</b>
<Media.Dropzone query={{ limit: 2 }} />
</div>
<div>
<b>Dropzone Container blank</b>
<Media.Dropzone />
</div>
<div>
<b>Dropzone Post 12</b>
<Media.Dropzone entity={{ name: "posts", id: 12, field: "images" }} />
</div>
</div>
</Scrollable>
);
}
function CustomUserAvatarDropzone({
wrapperRef,
inputProps,
state: { files, isOver, isOverAccepted, showPlaceholder },
actions: { openFileInput }
}: DropzoneRenderProps) {
const file = files[0];
return (
<div
ref={wrapperRef}
className="size-32 rounded-full border border-gray-200 flex justify-center items-center leading-none overflow-hidden"
>
<div className="hidden">
<input {...inputProps} />
</div>
{showPlaceholder && <>{isOver && isOverAccepted ? "let it drop" : "drop here"}</>}
{file && (
<Media.Preview
file={file}
className="object-cover w-full h-full"
onClick={openFileInput}
/>
)}
</div>
);
}