mirror of
https://github.com/usememos/memos.git
synced 2025-02-21 05:40:57 +01:00
feat: add list style for resource dashboard (#1389)
* stash: file upload * feat: add style button * feat: add style of list * feat: add checkbox for list * 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 * feat: support the style of button * feat: beautify the switch ui * chore: refactor the component * chore: refactor the resource item dropdown * feat: use memo to reduce unused computing in drop * feat: use memo to reduce the calc of resource list * chore:change name * 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 * feat: support to save the state of style * remove pnpm-lock * merge main * chore: simpify the statement * fix: delete conflict marker * feat: add i18n for select * feat:support dark mode * eslint * feat: delete the storage of resource style --------- Co-authored-by: boojack <stevenlgtm@gmail.com>
This commit is contained in:
parent
e84d562146
commit
7d89fcc892
@ -1,74 +1,26 @@
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { toast } from "react-hot-toast";
|
|
||||||
import { useResourceStore } from "../store/module";
|
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import copy from "copy-to-clipboard";
|
|
||||||
import { getResourceUrl } from "../utils/resource";
|
|
||||||
import showPreviewImageDialog from "./PreviewImageDialog";
|
|
||||||
import Dropdown from "./base/Dropdown";
|
|
||||||
import ResourceCover from "./ResourceCover";
|
import ResourceCover from "./ResourceCover";
|
||||||
import { showCommonDialog } from "./Dialog/CommonDialog";
|
|
||||||
import showChangeResourceFilenameDialog from "./ChangeResourceFilenameDialog";
|
|
||||||
import "../less/resource-card.less";
|
import "../less/resource-card.less";
|
||||||
|
import ResourceItemDropdown from "./ResourceItemDropdown";
|
||||||
|
|
||||||
interface ResourceProps {
|
const ResourceCard = ({
|
||||||
resource: Resource;
|
resource,
|
||||||
handlecheckClick: () => void;
|
handleCheckClick,
|
||||||
handleUncheckClick: () => void;
|
handleUncheckClick,
|
||||||
}
|
handlePreviewBtnClick,
|
||||||
|
handleCopyResourceLinkBtnClick,
|
||||||
const ResourceCard = ({ resource, handlecheckClick, handleUncheckClick }: ResourceProps) => {
|
handleRenameBtnClick,
|
||||||
|
handleDeleteResourceBtnClick,
|
||||||
|
}: ResourceItemType) => {
|
||||||
const [isSelected, setIsSelected] = useState<boolean>(false);
|
const [isSelected, setIsSelected] = useState<boolean>(false);
|
||||||
const resourceStore = useResourceStore();
|
|
||||||
const resources = resourceStore.state.resources;
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const handleRenameBtnClick = (resource: Resource) => {
|
|
||||||
showChangeResourceFilenameDialog(resource.id, resource.filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteResourceBtnClick = (resource: Resource) => {
|
|
||||||
let warningText = t("resources.warning-text");
|
|
||||||
if (resource.linkedMemoAmount > 0) {
|
|
||||||
warningText = warningText + `\n${t("resources.linked-amount")}: ${resource.linkedMemoAmount}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
showCommonDialog({
|
|
||||||
title: t("resources.delete-resource"),
|
|
||||||
content: warningText,
|
|
||||||
style: "warning",
|
|
||||||
dialogName: "delete-resource-dialog",
|
|
||||||
onConfirm: async () => {
|
|
||||||
await resourceStore.deleteResourceById(resource.id);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePreviewBtnClick = (resource: Resource) => {
|
|
||||||
const resourceUrl = getResourceUrl(resource);
|
|
||||||
if (resource.type.startsWith("image")) {
|
|
||||||
showPreviewImageDialog(
|
|
||||||
resources.filter((r) => r.type.startsWith("image")).map((r) => getResourceUrl(r)),
|
|
||||||
resources.findIndex((r) => r.id === resource.id)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
window.open(resourceUrl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCopyResourceLinkBtnClick = (resource: Resource) => {
|
|
||||||
const url = getResourceUrl(resource);
|
|
||||||
copy(url);
|
|
||||||
toast.success(t("message.succeed-copy-resource-link"));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSelectBtnClick = () => {
|
const handleSelectBtnClick = () => {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
handleUncheckClick();
|
handleUncheckClick();
|
||||||
} else {
|
} else {
|
||||||
handlecheckClick();
|
handleCheckClick();
|
||||||
}
|
}
|
||||||
setIsSelected(!isSelected);
|
setIsSelected(!isSelected);
|
||||||
};
|
};
|
||||||
@ -79,41 +31,16 @@ const ResourceCard = ({ resource, handlecheckClick, handleUncheckClick }: Resour
|
|||||||
<div onClick={() => handleSelectBtnClick()}>
|
<div onClick={() => handleSelectBtnClick()}>
|
||||||
{isSelected ? <Icon.CheckCircle2 className="resource-checkbox !flex" /> : <Icon.Circle className="resource-checkbox" />}
|
{isSelected ? <Icon.CheckCircle2 className="resource-checkbox !flex" /> : <Icon.Circle className="resource-checkbox" />}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="more-action-btn">
|
||||||
<Dropdown
|
<ResourceItemDropdown
|
||||||
className="more-action-btn"
|
resource={resource}
|
||||||
actionsClassName="!w-28"
|
handleCopyResourceLinkBtnClick={handleCopyResourceLinkBtnClick}
|
||||||
trigger={<Icon.MoreVertical className="w-4 h-auto hover:opacity-80 cursor-pointer" />}
|
handleDeleteResourceBtnClick={handleDeleteResourceBtnClick}
|
||||||
actions={
|
handlePreviewBtnClick={handlePreviewBtnClick}
|
||||||
<>
|
handleRenameBtnClick={handleRenameBtnClick}
|
||||||
<button
|
|
||||||
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
|
||||||
onClick={() => handlePreviewBtnClick(resource)}
|
|
||||||
>
|
|
||||||
{t("resources.preview")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
|
||||||
onClick={() => handleCopyResourceLinkBtnClick(resource)}
|
|
||||||
>
|
|
||||||
{t("resources.copy-link")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
|
||||||
onClick={() => handleRenameBtnClick(resource)}
|
|
||||||
>
|
|
||||||
{t("resources.rename")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded text-red-600 hover:bg-gray-100 dark:hover:bg-zinc-600"
|
|
||||||
onClick={() => handleDeleteResourceBtnClick(resource)}
|
|
||||||
>
|
|
||||||
{t("common.delete")}
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="w-full flex flex-row justify-center items-center pb-2 pt-4 px-2">
|
<div className="w-full flex flex-row justify-center items-center pb-2 pt-4 px-2">
|
||||||
<ResourceCover resource={resource} />
|
<ResourceCover resource={resource} />
|
||||||
</div>
|
</div>
|
||||||
|
46
web/src/components/ResourceItem.tsx
Normal file
46
web/src/components/ResourceItem.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import ResourceItemDropdown from "./ResourceItemDropdown";
|
||||||
|
|
||||||
|
const ResourceItem = ({
|
||||||
|
resource,
|
||||||
|
handleCheckClick,
|
||||||
|
handleUncheckClick,
|
||||||
|
handlePreviewBtnClick,
|
||||||
|
handleCopyResourceLinkBtnClick,
|
||||||
|
handleRenameBtnClick,
|
||||||
|
handleDeleteResourceBtnClick,
|
||||||
|
}: ResourceItemType) => {
|
||||||
|
const [isSelected, setIsSelected] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleSelectBtnClick = () => {
|
||||||
|
if (isSelected) {
|
||||||
|
handleUncheckClick();
|
||||||
|
} else {
|
||||||
|
handleCheckClick();
|
||||||
|
}
|
||||||
|
setIsSelected(!isSelected);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={resource.id} className="px-2 py-2 w-full grid grid-cols-7">
|
||||||
|
<span className="w-full m-auto truncate col-span-1 justify-center">
|
||||||
|
<input type="checkbox" onClick={handleSelectBtnClick}></input>
|
||||||
|
</span>
|
||||||
|
<span className="w-full m-auto truncate text-base pr-2 last:pr-0 col-span-1">{resource.id}</span>
|
||||||
|
<span className="w-full m-auto truncate text-base pr-2 last:pr-0 col-span-4" onClick={() => handleRenameBtnClick(resource)}>
|
||||||
|
{resource.filename}
|
||||||
|
</span>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||||
|
<ResourceItemDropdown
|
||||||
|
resource={resource}
|
||||||
|
handleCopyResourceLinkBtnClick={handleCopyResourceLinkBtnClick}
|
||||||
|
handleDeleteResourceBtnClick={handleDeleteResourceBtnClick}
|
||||||
|
handlePreviewBtnClick={handlePreviewBtnClick}
|
||||||
|
handleRenameBtnClick={handleRenameBtnClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResourceItem;
|
59
web/src/components/ResourceItemDropdown.tsx
Normal file
59
web/src/components/ResourceItemDropdown.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Dropdown from "./base/Dropdown";
|
||||||
|
import Icon from "./Icon";
|
||||||
|
|
||||||
|
interface ResourceItemDropdown {
|
||||||
|
resource: Resource;
|
||||||
|
handleRenameBtnClick: (resource: Resource) => void;
|
||||||
|
handleDeleteResourceBtnClick: (resource: Resource) => void;
|
||||||
|
handlePreviewBtnClick: (resource: Resource) => void;
|
||||||
|
handleCopyResourceLinkBtnClick: (resource: Resource) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResourceItemDropdown = ({
|
||||||
|
resource,
|
||||||
|
handlePreviewBtnClick,
|
||||||
|
handleCopyResourceLinkBtnClick,
|
||||||
|
handleRenameBtnClick,
|
||||||
|
handleDeleteResourceBtnClick,
|
||||||
|
}: ResourceItemDropdown) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
actionsClassName="!w-28"
|
||||||
|
trigger={<Icon.MoreVertical className="w-4 h-auto hover:opacity-80 cursor-pointer" />}
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
||||||
|
onClick={() => handlePreviewBtnClick(resource)}
|
||||||
|
>
|
||||||
|
{t("resources.preview")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
||||||
|
onClick={() => handleCopyResourceLinkBtnClick(resource)}
|
||||||
|
>
|
||||||
|
{t("resources.copy-link")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
||||||
|
onClick={() => handleRenameBtnClick(resource)}
|
||||||
|
>
|
||||||
|
{t("resources.rename")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded text-red-600 hover:bg-gray-100 dark:hover:bg-zinc-600"
|
||||||
|
onClick={() => handleDeleteResourceBtnClick(resource)}
|
||||||
|
>
|
||||||
|
{t("common.delete")}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(ResourceItemDropdown);
|
17
web/src/hooks/useListStyle.ts
Normal file
17
web/src/hooks/useListStyle.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const useListStyle = () => {
|
||||||
|
// true is Table Style, false is Grid Style
|
||||||
|
const [listStyle, setListStyle] = useState(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
listStyle: listStyle,
|
||||||
|
setToTableStyle: () => {
|
||||||
|
setListStyle(true);
|
||||||
|
},
|
||||||
|
setToGridStyle: () => {
|
||||||
|
setListStyle(false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export default useListStyle;
|
@ -81,7 +81,8 @@
|
|||||||
"delete-selected-resources": "Delete Selected Resources",
|
"delete-selected-resources": "Delete Selected Resources",
|
||||||
"no-files-selected": "No files selected❗",
|
"no-files-selected": "No files selected❗",
|
||||||
"upload-successfully": "Upload successfully",
|
"upload-successfully": "Upload successfully",
|
||||||
"file-drag-drop-prompt": "Drag and drop your file here to upload file"
|
"file-drag-drop-prompt": "Drag and drop your file here to upload file",
|
||||||
|
"select": "Select"
|
||||||
},
|
},
|
||||||
"archived": {
|
"archived": {
|
||||||
"archived-memos": "Archived Memos",
|
"archived-memos": "Archived Memos",
|
||||||
|
@ -81,7 +81,8 @@
|
|||||||
"delete-selected-resources": "刪除選中資源",
|
"delete-selected-resources": "刪除選中資源",
|
||||||
"no-files-selected": "沒有文件被選中❗",
|
"no-files-selected": "沒有文件被選中❗",
|
||||||
"upload-successfully": "上傳成功",
|
"upload-successfully": "上傳成功",
|
||||||
"file-drag-drop-prompt": "將您的文件拖放到此處以上傳文件"
|
"file-drag-drop-prompt": "將您的文件拖放到此處以上傳文件",
|
||||||
|
"select": "選擇"
|
||||||
},
|
},
|
||||||
"archived": {
|
"archived": {
|
||||||
"archived-memos": "已封存的 Memo",
|
"archived-memos": "已封存的 Memo",
|
||||||
|
@ -81,7 +81,8 @@
|
|||||||
"delete-selected-resources": "删除选中资源",
|
"delete-selected-resources": "删除选中资源",
|
||||||
"no-files-selected": "没有文件被选中❗",
|
"no-files-selected": "没有文件被选中❗",
|
||||||
"upload-successfully": "上传成功",
|
"upload-successfully": "上传成功",
|
||||||
"file-drag-drop-prompt": "将您的文件拖放到此处以上传文件"
|
"file-drag-drop-prompt": "将您的文件拖放到此处以上传文件",
|
||||||
|
"select": "选择"
|
||||||
},
|
},
|
||||||
"archived": {
|
"archived": {
|
||||||
"archived-memos": "已归档的 Memo",
|
"archived-memos": "已归档的 Memo",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Button } from "@mui/joy";
|
import { Button } from "@mui/joy";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
@ -7,10 +7,16 @@ import { useResourceStore } from "../store/module";
|
|||||||
import Icon from "../components/Icon";
|
import Icon from "../components/Icon";
|
||||||
import ResourceCard from "../components/ResourceCard";
|
import ResourceCard from "../components/ResourceCard";
|
||||||
import ResourceSearchBar from "../components/ResourceSearchBar";
|
import ResourceSearchBar from "../components/ResourceSearchBar";
|
||||||
import { showCommonDialog } from "../components/Dialog/CommonDialog";
|
|
||||||
import showCreateResourceDialog from "../components/CreateResourceDialog";
|
|
||||||
import MobileHeader from "../components/MobileHeader";
|
import MobileHeader from "../components/MobileHeader";
|
||||||
import Dropdown from "../components/base/Dropdown";
|
import Dropdown from "../components/base/Dropdown";
|
||||||
|
import ResourceItem from "../components/ResourceItem";
|
||||||
|
import { showCommonDialog } from "../components/Dialog/CommonDialog";
|
||||||
|
import showChangeResourceFilenameDialog from "../components/ChangeResourceFilenameDialog";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
import { getResourceUrl } from "../utils/resource";
|
||||||
|
import showPreviewImageDialog from "../components/PreviewImageDialog";
|
||||||
|
import showCreateResourceDialog from "../components/CreateResourceDialog";
|
||||||
|
import useListStyle from "../hooks/useListStyle";
|
||||||
|
|
||||||
const ResourcesDashboard = () => {
|
const ResourcesDashboard = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -20,6 +26,7 @@ const ResourcesDashboard = () => {
|
|||||||
const [selectedList, setSelectedList] = useState<Array<ResourceId>>([]);
|
const [selectedList, setSelectedList] = useState<Array<ResourceId>>([]);
|
||||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||||
const [queryText, setQueryText] = useState<string>("");
|
const [queryText, setQueryText] = useState<string>("");
|
||||||
|
const { listStyle, setToTableStyle, setToGridStyle } = useListStyle();
|
||||||
const [dragActive, setDragActive] = useState(false);
|
const [dragActive, setDragActive] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -95,6 +102,86 @@ const ResourcesDashboard = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleStyleChangeBtnClick = (listStyleValue: boolean) => {
|
||||||
|
if (listStyleValue) {
|
||||||
|
setToTableStyle();
|
||||||
|
} else {
|
||||||
|
setToGridStyle();
|
||||||
|
}
|
||||||
|
setSelectedList([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameBtnClick = (resource: Resource) => {
|
||||||
|
showChangeResourceFilenameDialog(resource.id, resource.filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteResourceBtnClick = (resource: Resource) => {
|
||||||
|
let warningText = t("resources.warning-text");
|
||||||
|
if (resource.linkedMemoAmount > 0) {
|
||||||
|
warningText = warningText + `\n${t("resources.linked-amount")}: ${resource.linkedMemoAmount}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
showCommonDialog({
|
||||||
|
title: t("resources.delete-resource"),
|
||||||
|
content: warningText,
|
||||||
|
style: "warning",
|
||||||
|
dialogName: "delete-resource-dialog",
|
||||||
|
onConfirm: async () => {
|
||||||
|
await resourceStore.deleteResourceById(resource.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePreviewBtnClick = (resource: Resource) => {
|
||||||
|
const resourceUrl = getResourceUrl(resource);
|
||||||
|
if (resource.type.startsWith("image")) {
|
||||||
|
showPreviewImageDialog(
|
||||||
|
resources.filter((r) => r.type.startsWith("image")).map((r) => getResourceUrl(r)),
|
||||||
|
resources.findIndex((r) => r.id === resource.id)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
window.open(resourceUrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCopyResourceLinkBtnClick = (resource: Resource) => {
|
||||||
|
const url = getResourceUrl(resource);
|
||||||
|
copy(url);
|
||||||
|
toast.success(t("message.succeed-copy-resource-link"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const resourceList = useMemo(
|
||||||
|
() =>
|
||||||
|
resources
|
||||||
|
.filter((res: Resource) => (queryText === "" ? true : res.filename.toLowerCase().includes(queryText.toLowerCase())))
|
||||||
|
.map((resource) =>
|
||||||
|
listStyle ? (
|
||||||
|
<ResourceItem
|
||||||
|
key={resource.id}
|
||||||
|
resource={resource}
|
||||||
|
handleCheckClick={() => handleCheckBtnClick(resource.id)}
|
||||||
|
handleUncheckClick={() => handleUncheckBtnClick(resource.id)}
|
||||||
|
handleRenameBtnClick={handleRenameBtnClick}
|
||||||
|
handleDeleteResourceBtnClick={handleDeleteResourceBtnClick}
|
||||||
|
handlePreviewBtnClick={handlePreviewBtnClick}
|
||||||
|
handleCopyResourceLinkBtnClick={handleCopyResourceLinkBtnClick}
|
||||||
|
></ResourceItem>
|
||||||
|
) : (
|
||||||
|
<ResourceCard
|
||||||
|
key={resource.id}
|
||||||
|
resource={resource}
|
||||||
|
handleCheckClick={() => handleCheckBtnClick(resource.id)}
|
||||||
|
handleUncheckClick={() => handleUncheckBtnClick(resource.id)}
|
||||||
|
handleRenameBtnClick={handleRenameBtnClick}
|
||||||
|
handleDeleteResourceBtnClick={handleDeleteResourceBtnClick}
|
||||||
|
handlePreviewBtnClick={handlePreviewBtnClick}
|
||||||
|
handleCopyResourceLinkBtnClick={handleCopyResourceLinkBtnClick}
|
||||||
|
></ResourceCard>
|
||||||
|
)
|
||||||
|
),
|
||||||
|
[resources, queryText, listStyle]
|
||||||
|
);
|
||||||
|
|
||||||
const handleDrag = (e: React.DragEvent<HTMLDivElement>) => {
|
const handleDrag = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -157,6 +244,20 @@ const ResourcesDashboard = () => {
|
|||||||
<Button onClick={() => showCreateResourceDialog({})}>
|
<Button onClick={() => showCreateResourceDialog({})}>
|
||||||
<Icon.Plus className="w-4 h-auto" />
|
<Icon.Plus className="w-4 h-auto" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<div className="flex">
|
||||||
|
<div
|
||||||
|
className={`rounded-l-lg p-2 ${listStyle ? "bg-gray-200 dark:bg-zinc-800" : "bg-white bg-zinc-700"}`}
|
||||||
|
onClick={() => handleStyleChangeBtnClick(true)}
|
||||||
|
>
|
||||||
|
<Icon.List />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`rounded-r-lg p-2 ${listStyle ? "bg-white bg-zinc-700" : "bg-gray-200 dark:bg-zinc-800"}`}
|
||||||
|
onClick={() => handleStyleChangeBtnClick(false)}
|
||||||
|
>
|
||||||
|
<Icon.Grid />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
className="drop-shadow-none"
|
className="drop-shadow-none"
|
||||||
actionsClassName="!w-28 rounded-lg drop-shadow-md dark:bg-zinc-800"
|
actionsClassName="!w-28 rounded-lg drop-shadow-md dark:bg-zinc-800"
|
||||||
@ -185,20 +286,25 @@ const ResourcesDashboard = () => {
|
|||||||
<p className="w-full text-center text-base my-6 mt-8">{t("resources.fetching-data")}</p>
|
<p className="w-full text-center text-base my-6 mt-8">{t("resources.fetching-data")}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full h-auto grid grid-cols-2 md:grid-cols-4 md:px-6 gap-6">
|
<div
|
||||||
|
className={
|
||||||
|
listStyle
|
||||||
|
? "flex flex-col justify-start items-start w-full"
|
||||||
|
: "w-full h-auto grid grid-cols-2 md:grid-cols-4 md:px-6 gap-6"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{listStyle && (
|
||||||
|
<div className="px-2 py-2 w-full grid grid-cols-7 border-b dark:border-b-zinc-600">
|
||||||
|
<span>{t("resources.select")}</span>
|
||||||
|
<span className="field-text id-text">ID</span>
|
||||||
|
<span className="field-text name-text">{t("resources.name")}</span>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{resources.length === 0 ? (
|
{resources.length === 0 ? (
|
||||||
<p className="w-full text-center text-base my-6 mt-8">{t("resources.no-resources")}</p>
|
<p className="w-full text-center text-base my-6 mt-8">{t("resources.no-resources")}</p>
|
||||||
) : (
|
) : (
|
||||||
resources
|
resourceList
|
||||||
.filter((res: Resource) => (queryText === "" ? true : res.filename.toLowerCase().includes(queryText.toLowerCase())))
|
|
||||||
.map((resource) => (
|
|
||||||
<ResourceCard
|
|
||||||
key={resource.id}
|
|
||||||
resource={resource}
|
|
||||||
handlecheckClick={() => handleCheckBtnClick(resource.id)}
|
|
||||||
handleUncheckClick={() => handleUncheckBtnClick(resource.id)}
|
|
||||||
></ResourceCard>
|
|
||||||
))
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
11
web/src/types/resourceItem.d.ts
vendored
Normal file
11
web/src/types/resourceItem.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
interface ResourceProps {
|
||||||
|
resource: Resource;
|
||||||
|
handleCheckClick: () => void;
|
||||||
|
handleUncheckClick: () => void;
|
||||||
|
handleRenameBtnClick: (resource: Resource) => void;
|
||||||
|
handleDeleteResourceBtnClick: (resource: Resource) => void;
|
||||||
|
handlePreviewBtnClick: (resource: Resource) => void;
|
||||||
|
handleCopyResourceLinkBtnClick: (resource: Resource) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResourceItemType = ResourceProps;
|
Loading…
x
Reference in New Issue
Block a user