frontend/src/component/FileManager/Explorer/GridView/GridView.tsx
2025-06-22 10:57:50 +08:00

151 lines
4.7 KiB
TypeScript

import React, { useContext, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Box, Grid, Stack, styled, Typography } from "@mui/material";
import { useAppSelector } from "../../../../redux/hooks.ts";
import { FileResponse, FileType } from "../../../../api/explorer.ts";
import DndWrappedFile from "../../Dnd/DndWrappedFile.tsx";
import { FmIndexContext } from "../../FmIndexContext.tsx";
import GridFile from "./GridFile.tsx";
export interface GridViewProps {
[key: string]: any;
}
export interface FmFile extends FileResponse {
id: string;
first?: boolean;
placeholder?: boolean;
}
interface listComponents {
Folders?: JSX.Element[];
Files: JSX.Element[];
}
const AutoFillGrid = styled(Grid)(({ theme }) => ({
[theme.breakpoints.down("md")]: {
gridTemplateColumns: "repeat(auto-fill,minmax(160px,1fr))!important",
},
[theme.breakpoints.up("md")]: {
gridTemplateColumns: "repeat(auto-fill,minmax(220px,1fr))!important",
},
gridGap: theme.spacing(2),
display: "grid!important",
padding: theme.spacing(1),
}));
const GridItem = styled(Grid)(() => ({
flex: "1 1 220px!important",
}));
export const loadingPlaceHolderNumb = 3;
const GridView = React.forwardRef(({ ...rest }: GridViewProps, ref) => {
const { t } = useTranslation("application");
const fmIndex = useContext(FmIndexContext);
const files = useAppSelector((state) => state.fileManager[fmIndex].list?.files);
const mixedType = useAppSelector((state) => state.fileManager[fmIndex].list?.mixed_type);
const pagination = useAppSelector((state) => state.fileManager[fmIndex].list?.pagination);
const showThumb = useAppSelector((state) => state.fileManager[fmIndex].showThumb);
const search_params = useAppSelector((state) => state.fileManager[fmIndex]?.search_params);
const list = useMemo(() => {
const list: listComponents = {
Files: [],
};
if (files) {
files.forEach((file, index) => {
if (file.type === FileType.folder && !mixedType) {
if (!list.Folders) {
list.Folders = [];
}
list.Folders.push(
<GridItem item key={`${file.id}`}>
<DndWrappedFile
component={GridFile}
search={search_params}
index={index}
showThumb={mixedType}
file={file}
/>
</GridItem>,
);
} else {
list.Files.push(
<GridItem item key={`${file.id}`}>
<DndWrappedFile
component={GridFile}
search={search_params}
index={index}
showThumb={showThumb}
file={file}
/>
</GridItem>,
);
}
});
// Add loading placeholder if there is next page
if (pagination && pagination.next_token) {
for (let i = 0; i < loadingPlaceHolderNumb; i++) {
const id = `loadingPlaceholder-${pagination.next_token}-${i}`;
const loadingPlaceholder = (
<GridItem item key={id}>
<DndWrappedFile
component={GridFile}
showThumb={list.Files.length > 0 ? showThumb : mixedType}
file={{
...files[0],
path: files[0].path + "/" + id,
id: `loadingPlaceholder-${pagination.next_token}-${i}`,
first: i == 0,
placeholder: true,
}}
/>
</GridItem>
);
const _ =
list.Files.length > 0 ? list.Files.push(loadingPlaceholder) : list.Folders?.push(loadingPlaceholder);
}
}
}
return list;
}, [files, mixedType, pagination, showThumb]);
return (
<Box
ref={ref}
{...rest}
sx={{
p: 1,
}}
>
<Stack spacing={1}>
{list.Folders && list.Folders.length > 0 && (
<Box>
<Typography fontWeight={"medium"} sx={{ p: 1 }} variant="body2">
{t("fileManager.folders")}
</Typography>
<AutoFillGrid container alignItems="flex-start" spacing={0}>
{list.Folders.map((f) => f)}
</AutoFillGrid>
</Box>
)}
{list.Files.length > 0 && (
<Box>
{!mixedType && (
<Typography sx={{ p: 1 }} fontWeight={"medium"} variant="body2">
{t("fileManager.files")}
</Typography>
)}
<AutoFillGrid container alignItems="flex-start" spacing={0}>
{list.Files.map((f) => f)}
</AutoFillGrid>
</Box>
)}
</Stack>
</Box>
);
});
export default GridView;