mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
feat: upload file by drag and drop (#1388)
* stash: file upload * feat: support file upload by drag * feat: beautify the ui * feat: support file upload * stash * fix: the resource is incorrectly when upload multiple files * feat: beautify the ui * chore: reduce unused line * stash * chore: deleted unused line * chore: deleted unused line * chore * chore: change the function declare * feat: support to prompt file is too large * feat:drop prompt to cover all element * fix: eslint * fix: the name of i18n * chore: refactor the import deps * feat: beautify the ui * Update web/src/locales/en.json Co-authored-by: boojack <stevenlgtm@gmail.com> * chore: the import of deps * fix: the window size of fecting data --------- Co-authored-by: boojack <stevenlgtm@gmail.com>
This commit is contained in:
@@ -79,7 +79,9 @@
|
||||
"no-unused-resources": "No unused resources",
|
||||
"name": "Name",
|
||||
"delete-selected-resources": "Delete Selected Resources",
|
||||
"no-files-selected": "No files selected❗"
|
||||
"no-files-selected": "No files selected❗",
|
||||
"upload-successfully": "Upload successfully",
|
||||
"file-drag-drop-prompt": "Drag and drop your file here to upload file"
|
||||
},
|
||||
"archived": {
|
||||
"archived-memos": "Archived Memos",
|
||||
|
@@ -79,7 +79,9 @@
|
||||
"no-unused-resources": "無可刪除的資源",
|
||||
"name": "資源名稱",
|
||||
"delete-selected-resources": "刪除選中資源",
|
||||
"no-files-selected": "沒有文件被選中❗"
|
||||
"no-files-selected": "沒有文件被選中❗",
|
||||
"upload-successfully": "上傳成功",
|
||||
"file-drag-drop-prompt": "將您的文件拖放到此處以上傳文件"
|
||||
},
|
||||
"archived": {
|
||||
"archived-memos": "已封存的 Memo",
|
||||
|
@@ -79,7 +79,9 @@
|
||||
"no-unused-resources": "无可删除的资源",
|
||||
"name": "资源名称",
|
||||
"delete-selected-resources": "删除选中资源",
|
||||
"no-files-selected": "没有文件被选中❗"
|
||||
"no-files-selected": "没有文件被选中❗",
|
||||
"upload-successfully": "上传成功",
|
||||
"file-drag-drop-prompt": "将您的文件拖放到此处以上传文件"
|
||||
},
|
||||
"archived": {
|
||||
"archived-memos": "已归档的 Memo",
|
||||
|
@@ -20,6 +20,7 @@ const ResourcesDashboard = () => {
|
||||
const [selectedList, setSelectedList] = useState<Array<ResourceId>>([]);
|
||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||
const [queryText, setQueryText] = useState<string>("");
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
resourceStore
|
||||
@@ -94,9 +95,52 @@ const ResourcesDashboard = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrag = (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.type === "dragenter" || e.type === "dragover") {
|
||||
setDragActive(true);
|
||||
} else if (e.type === "dragleave") {
|
||||
setDragActive(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(false);
|
||||
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
|
||||
await resourceStore.createResourcesWithBlob(e.dataTransfer.files).then(
|
||||
(res) => {
|
||||
for (const resource of res) {
|
||||
toast.success(`${resource.filename} ${t("resources.upload-successfully")}`);
|
||||
}
|
||||
},
|
||||
(reason) => {
|
||||
toast.error(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="w-full max-w-2xl min-h-full flex flex-col justify-start items-center px-4 sm:px-2 sm:pt-4 pb-8 bg-zinc-100 dark:bg-zinc-800">
|
||||
<MobileHeader showSearch={false} />
|
||||
<div className="w-full relative" onDragEnter={handleDrag}>
|
||||
{dragActive && (
|
||||
<div
|
||||
className="absolute h-full w-full rounded-xl bg-zinc-800 dark:bg-white opacity-60 z-10"
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<div className="flex h-full w-full">
|
||||
<p className="m-auto text-2xl text-white dark:text-black">{t("resources.file-drag-drop-prompt")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="w-full flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="flex flex-row justify-start items-center select-none rounded">
|
||||
@@ -160,6 +204,7 @@ const ResourcesDashboard = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
@@ -47,6 +47,24 @@ export const useResourceStore = () => {
|
||||
store.dispatch(setResources([resource, ...resourceList]));
|
||||
return resource;
|
||||
},
|
||||
async createResourcesWithBlob(files: FileList): Promise<Array<Resource>> {
|
||||
let newResourceList: Array<Resource> = [];
|
||||
for (const file of files) {
|
||||
const { name: filename, size } = file;
|
||||
if (size > MAX_FILE_SIZE) {
|
||||
return Promise.reject(`${filename} overload max size: 32MB`);
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", file, filename);
|
||||
const { data } = (await api.createResourceWithBlob(formData)).data;
|
||||
const resource = convertResponseModelResource(data);
|
||||
newResourceList = [resource, ...newResourceList];
|
||||
}
|
||||
const resourceList = state.resources;
|
||||
store.dispatch(setResources([...newResourceList, ...resourceList]));
|
||||
return newResourceList;
|
||||
},
|
||||
async deleteResourceById(id: ResourceId) {
|
||||
await api.deleteResourceById(id);
|
||||
store.dispatch(deleteResource(id));
|
||||
|
Reference in New Issue
Block a user