mirror of
https://github.com/coaidev/coai.git
synced 2025-05-20 05:20:15 +09:00
fix draggable file input
This commit is contained in:
parent
d9e821f43b
commit
f0eacf2aba
@ -12,6 +12,7 @@ import {
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Alert, AlertTitle } from "./ui/alert.tsx";
|
import { Alert, AlertTitle } from "./ui/alert.tsx";
|
||||||
import { useToast } from "./ui/use-toast.ts";
|
import { useToast } from "./ui/use-toast.ts";
|
||||||
|
import {useDraggableInput} from "../utils.ts";
|
||||||
|
|
||||||
export type FileObject = {
|
export type FileObject = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -19,7 +20,7 @@ export type FileObject = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FileProviderProps = {
|
type FileProviderProps = {
|
||||||
id?: string;
|
id: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
onChange?: (data: FileObject) => void;
|
onChange?: (data: FileObject) => void;
|
||||||
@ -27,9 +28,10 @@ type FileProviderProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type FileObjectProps = {
|
type FileObjectProps = {
|
||||||
id?: string;
|
id: string;
|
||||||
|
filename: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
onChange?: (filename: string, data: string) => void;
|
onChange?: (filename?: string, data?: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function FileProvider({
|
function FileProvider({
|
||||||
@ -43,7 +45,6 @@ function FileProvider({
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [active, setActive] = useState(false);
|
const [active, setActive] = useState(false);
|
||||||
const [filename, setFilename] = useState<string>("");
|
const [filename, setFilename] = useState<string>("");
|
||||||
const ref = useRef<HTMLLabelElement | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setClearEvent && setClearEvent(() => clear);
|
setClearEvent && setClearEvent(() => clear);
|
||||||
@ -53,48 +54,6 @@ function FileProvider({
|
|||||||
}
|
}
|
||||||
}, [setClearEvent]);
|
}, [setClearEvent]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!ref.current) return;
|
|
||||||
const target = ref.current as HTMLLabelElement;
|
|
||||||
|
|
||||||
target.addEventListener("dragover", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
target.addEventListener("drop", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const file = e.dataTransfer?.files?.[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (e) => {
|
|
||||||
const data = e.target?.result as string;
|
|
||||||
if (!/^[\x00-\x7F]*$/.test(data)) {
|
|
||||||
toast({
|
|
||||||
title: t("file.parse-error"),
|
|
||||||
description: t("file.parse-error-prompt"),
|
|
||||||
});
|
|
||||||
handleChange();
|
|
||||||
} else {
|
|
||||||
handleChange(e.target?.result as string);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.readAsText(file);
|
|
||||||
} else {
|
|
||||||
handleChange();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
target.addEventListener("dragleave", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
target.removeEventListener("dragover", () => {});
|
|
||||||
target.removeEventListener("drop", () => {});
|
|
||||||
}
|
|
||||||
}, [ref]);
|
|
||||||
|
|
||||||
function clear() {
|
function clear() {
|
||||||
setFilename("");
|
setFilename("");
|
||||||
setActive(false);
|
setActive(false);
|
||||||
@ -143,47 +102,43 @@ function FileProvider({
|
|||||||
<AlertCircle className="h-4 w-4" />
|
<AlertCircle className="h-4 w-4" />
|
||||||
<AlertTitle>{t("file.type")}</AlertTitle>
|
<AlertTitle>{t("file.type")}</AlertTitle>
|
||||||
</Alert>
|
</Alert>
|
||||||
<label className={`drop-window`} htmlFor={id} ref={ref}>
|
<FileObject
|
||||||
{filename ? (
|
id={id}
|
||||||
<div className={`file-object`}>
|
filename={filename}
|
||||||
<File className={`h-4 w-4`} />
|
className={className}
|
||||||
<p>{filename}</p>
|
onChange={handleChange}
|
||||||
<X
|
|
||||||
className={`h-3.5 w-3.5 ml-1 close`}
|
|
||||||
onClick={(e) => {
|
|
||||||
handleChange();
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<p>{t("file.drop")}</p>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<FileObject
|
|
||||||
id={id}
|
|
||||||
className={className}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileObject({
|
function FileObject({
|
||||||
id,
|
id,
|
||||||
|
filename,
|
||||||
className,
|
className,
|
||||||
onChange,
|
onChange,
|
||||||
}: FileObjectProps) {
|
}: FileObjectProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
useEffect(() => {
|
||||||
const file = e.target.files?.[0];
|
if (!ref.current) return;
|
||||||
|
const target = ref.current as HTMLLabelElement;
|
||||||
|
onChange && useDraggableInput(t, toast, target, onChange);
|
||||||
|
return () => {
|
||||||
|
target.removeEventListener("dragover", () => {});
|
||||||
|
target.removeEventListener("drop", () => {});
|
||||||
|
}
|
||||||
|
}, [ref]);
|
||||||
|
|
||||||
|
const handleChange = (e?: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e && e.target.files?.[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
@ -203,7 +158,26 @@ function FileObject({
|
|||||||
onChange?.("", "");
|
onChange?.("", "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<label className={`drop-window`} htmlFor={id} ref={ref}>
|
||||||
|
{filename ? (
|
||||||
|
<div className={`file-object`}>
|
||||||
|
<File className={`h-4 w-4`} />
|
||||||
|
<p>{filename}</p>
|
||||||
|
<X
|
||||||
|
className={`h-3.5 w-3.5 ml-1 close`}
|
||||||
|
onClick={(e) => {
|
||||||
|
handleChange();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p>{t("file.drop")}</p>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
id={id}
|
id={id}
|
||||||
type="file"
|
type="file"
|
||||||
@ -212,6 +186,7 @@ function FileObject({
|
|||||||
multiple={false}
|
multiple={false}
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,3 +156,39 @@ ${message}`;
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useDraggableInput(
|
||||||
|
t: any,
|
||||||
|
toast: any,
|
||||||
|
target: HTMLLabelElement,
|
||||||
|
handleChange: (filename?: string, content?: string) => void
|
||||||
|
) {
|
||||||
|
target.addEventListener("dragover", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
target.addEventListener("drop", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const file = e.dataTransfer?.files[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const data = e.target?.result as string;
|
||||||
|
if (!/^[\x00-\x7F]*$/.test(data)) {
|
||||||
|
toast({
|
||||||
|
title: t("file.parse-error"),
|
||||||
|
description: t("file.parse-error-prompt"),
|
||||||
|
});
|
||||||
|
handleChange();
|
||||||
|
} else {
|
||||||
|
handleChange(file.name, e.target?.result as string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
} else {
|
||||||
|
handleChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user