added media filter, improved search, ui changes
This commit is contained in:
@@ -413,6 +413,7 @@ class FileController {
|
||||
const startAtName = (query.startAtName as string) || undefined;
|
||||
const trashMode = query.trashMode === "true";
|
||||
const mediaMode = query.mediaMode === "true";
|
||||
const mediaFilter = (query.mediaFilter as string) || "all";
|
||||
|
||||
const queryData: FileListQueryType = {
|
||||
userID,
|
||||
@@ -423,6 +424,7 @@ class FileController {
|
||||
trashMode,
|
||||
mediaMode,
|
||||
sortBy,
|
||||
mediaFilter,
|
||||
};
|
||||
|
||||
const fileList = await fileService.getList(queryData, sortBy, limit);
|
||||
|
||||
@@ -40,6 +40,10 @@ export const getListValidationRules = [
|
||||
.optional()
|
||||
.isBoolean()
|
||||
.withMessage("Trash Mode must be a boolean"),
|
||||
query("mediaFilter")
|
||||
.optional()
|
||||
.isString()
|
||||
.withMessage("Media Filter must be a string"),
|
||||
query("mediaMode")
|
||||
.optional()
|
||||
.isBoolean()
|
||||
|
||||
@@ -9,11 +9,17 @@ type GenericParmasType = {
|
||||
export const createGenericParams = ({ filePath, Key }: GenericParmasType) => {
|
||||
// TODO: Remove file split after migration
|
||||
if (env.dbType === "fs") {
|
||||
const filePathSplit = filePath!.split("/");
|
||||
const fileName = filePathSplit[filePathSplit.length - 1];
|
||||
return {
|
||||
filePath: env.fsDirectory + fileName,
|
||||
};
|
||||
if (filePath?.includes("/")) {
|
||||
const filePathSplit = filePath!.split("/");
|
||||
const fileName = filePathSplit[filePathSplit.length - 1];
|
||||
return {
|
||||
filePath: env.fsDirectory + fileName,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
filePath: env.fsDirectory + Key!,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
Key,
|
||||
|
||||
@@ -7,4 +7,5 @@ export interface FileListQueryType {
|
||||
trashMode: boolean;
|
||||
mediaMode: boolean;
|
||||
sortBy: string;
|
||||
mediaFilter: string;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface FileQueryInterface {
|
||||
"metadata.personalFile"?: boolean | null;
|
||||
"metadata.trashed"?: boolean | null;
|
||||
"metadata.hasThumbnail"?: boolean | null;
|
||||
"metadata.isVideo"?: boolean | null;
|
||||
}
|
||||
|
||||
export const createFileQuery = ({
|
||||
@@ -30,6 +31,7 @@ export const createFileQuery = ({
|
||||
trashMode,
|
||||
mediaMode,
|
||||
sortBy,
|
||||
mediaFilter,
|
||||
}: FileListQueryType) => {
|
||||
const query: FileQueryInterface = { "metadata.owner": userID };
|
||||
|
||||
@@ -57,6 +59,12 @@ export const createFileQuery = ({
|
||||
|
||||
if (mediaMode) {
|
||||
query["metadata.hasThumbnail"] = true;
|
||||
|
||||
if (mediaFilter === "photos") {
|
||||
query["metadata.isVideo"] = false;
|
||||
} else if (mediaFilter === "videos") {
|
||||
query["metadata.isVideo"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
|
||||
@@ -39,7 +39,6 @@ const updateDocs = async () => {
|
||||
/\.(mp4|mov|avi|mkv|webm|wmv|flv|mpg|mpeg|3gp|3g2|mxf|ogv|ogg|m4v)$/i,
|
||||
},
|
||||
"metadata.thumbnailID": "",
|
||||
"metadata.owner": "670c8c321ebf0d4211617eb9",
|
||||
});
|
||||
|
||||
console.log("Found", files.length, "files");
|
||||
|
||||
@@ -12,6 +12,7 @@ interface QueryKeyParams {
|
||||
startAt?: boolean;
|
||||
trashMode?: boolean;
|
||||
mediaMode?: boolean;
|
||||
mediaFilter?: string;
|
||||
}
|
||||
|
||||
// GET
|
||||
@@ -29,6 +30,7 @@ export const getFilesListAPI = async ({
|
||||
limit = 50,
|
||||
trashMode,
|
||||
mediaMode,
|
||||
mediaFilter,
|
||||
},
|
||||
] = queryKey;
|
||||
|
||||
@@ -39,6 +41,7 @@ export const getFilesListAPI = async ({
|
||||
limit,
|
||||
trashMode,
|
||||
mediaMode,
|
||||
mediaFilter,
|
||||
};
|
||||
|
||||
if (pageParam?.startAtDate && pageParam?.startAtName) {
|
||||
|
||||
@@ -78,6 +78,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!wrapperRef.current) return;
|
||||
|
||||
const modalWidth = wrapperRef.current.clientWidth;
|
||||
const modalHeight = wrapperRef.current.clientHeight;
|
||||
|
||||
@@ -87,7 +88,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
|
||||
let Y = contextSelected.Y;
|
||||
|
||||
if (X + modalWidth > windowWidth) {
|
||||
X = windowWidth - windowWidth;
|
||||
X = windowWidth - modalWidth - 10;
|
||||
}
|
||||
|
||||
if (Y + modalHeight > windowHeight) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useFiles } from "../../hooks/files";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import React, { memo } from "react";
|
||||
import React, { memo, useMemo } from "react";
|
||||
import FileItem from "../FileItem/FileItem";
|
||||
import ParentBar from "../ParentBar/ParentBar";
|
||||
import classNames from "classnames";
|
||||
@@ -17,8 +17,18 @@ const Files = memo(() => {
|
||||
const changeListViewMode = () => {
|
||||
dispatch(toggleListView());
|
||||
};
|
||||
|
||||
const title = useMemo(() => {
|
||||
const hasFiles = !!files?.pages.find((file) => file);
|
||||
if (hasFiles) {
|
||||
return "Files";
|
||||
} else {
|
||||
return "No Files";
|
||||
}
|
||||
}, [files?.pages]);
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div className="mt-8 select-none">
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-5">
|
||||
{isHome && <h2 className="m-0 text-xl font-medium">Home Files</h2>}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useFolders } from "../../hooks/folders";
|
||||
import FolderItem from "../FolderItem/FolderItem";
|
||||
import { memo, useCallback } from "react";
|
||||
import { memo, useCallback, useMemo } from "react";
|
||||
import classNames from "classnames";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
@@ -8,7 +8,7 @@ import { setSortBy } from "../../reducers/filter";
|
||||
|
||||
const Folders = memo(() => {
|
||||
const { data: folders } = useFolders(false);
|
||||
const { isHome } = useUtils();
|
||||
const { isHome, isTrash, isSearch } = useUtils();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -65,16 +65,26 @@ const Folders = memo(() => {
|
||||
[sortBy]
|
||||
);
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (isTrash) {
|
||||
return "Trash";
|
||||
} else if (isSearch) {
|
||||
return "Search";
|
||||
} else {
|
||||
return folders?.length === 0 ? "No Folders" : "Folders";
|
||||
}
|
||||
}, [isHome, isTrash, isSearch, folders?.length]);
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div className="mt-8 select-none">
|
||||
<div className="flex flex-row mb-5 justify-between items-center">
|
||||
<h2
|
||||
className={classNames(
|
||||
"m-0 text-xl font-medium",
|
||||
isHome ? "block" : "invisible"
|
||||
"m-0 text-xl font-medium"
|
||||
// isHome || isTrash ? "block" : "invisible"
|
||||
)}
|
||||
>
|
||||
{folders?.length === 0 ? "No Folders" : "Folders"}
|
||||
{title}
|
||||
</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
|
||||
@@ -31,7 +31,7 @@ const Header = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<header id="header">
|
||||
<header id="header" className="select-none">
|
||||
<div className="px-6 flex justify-between min-h-16 items-center py-3.5">
|
||||
<div className="items-center w-[260px] hidden desktopMode:flex">
|
||||
<a
|
||||
|
||||
@@ -81,7 +81,7 @@ const LeftSection = () => {
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col h-full">
|
||||
<div className="flex flex-col h-full select-none">
|
||||
<div>
|
||||
<div className="relative mb-7">
|
||||
<a
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import classNames from "classnames";
|
||||
import React, { memo, useEffect, useMemo, useState } from "react";
|
||||
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import MediaItem from "../MediaItem/MediaItem";
|
||||
import { useFiles } from "../../hooks/files";
|
||||
import MultiSelectBar from "../MultiSelectBar/MultiSelectBar";
|
||||
import { useInfiniteScroll } from "../../hooks/infiniteScroll";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMediaFilter, setSortBy } from "../../reducers/filter";
|
||||
|
||||
const Medias = memo(() => {
|
||||
const {
|
||||
@@ -13,6 +15,9 @@ const Medias = memo(() => {
|
||||
} = useFiles();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const mediaFilter = useAppSelector((state) => state.filter.mediaFilter);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
@@ -26,8 +31,89 @@ const Medias = memo(() => {
|
||||
}
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
|
||||
const switchOrderSortBy = useCallback(() => {
|
||||
let newSortBy = "";
|
||||
switch (sortBy) {
|
||||
case "date_asc": {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
case "date_desc": {
|
||||
newSortBy = "date_asc";
|
||||
break;
|
||||
}
|
||||
case "alp_asc": {
|
||||
newSortBy = "alp_desc";
|
||||
break;
|
||||
}
|
||||
case "alp_desc": {
|
||||
newSortBy = "alp_asc";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
}, [sortBy]);
|
||||
|
||||
const mediaFilterOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
dispatch(setMediaFilter(value));
|
||||
};
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (mediaFilter === "all") {
|
||||
return "Photos and Videos";
|
||||
} else if (mediaFilter === "photos") {
|
||||
return "Photos";
|
||||
} else if (mediaFilter === "videos") {
|
||||
return "Videos";
|
||||
}
|
||||
}, [mediaFilter]);
|
||||
|
||||
return (
|
||||
<div className="w-full p-[17px_15px] desktopMode:p-[17px_40px] overflow-y-scroll">
|
||||
<div className="w-full p-[17px_15px] desktopMode:p-[17px_40px] overflow-y-scroll select-none">
|
||||
<div className="flex flex-row mb-5 justify-between items-center mt-2">
|
||||
<h2 className={classNames("m-0 text-xl font-medium")}>{title}</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
<svg
|
||||
className="h-3 w-3 cursor-pointer animate"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={
|
||||
sortBy === "date_desc" || sortBy === "alp_desc"
|
||||
? { transform: "scaleY(-1)" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<g id="upload">
|
||||
<path
|
||||
id="Path"
|
||||
d="M5.58035 2.51616L3.20339 0.139199C3.01776 -0.0463997 2.71681 -0.0463997 2.53119 0.139199L0.154195 2.51616C-0.0282007 2.70502 -0.0229639 3.00597 0.165894 3.18836C0.350128 3.3663 0.642189 3.3663 0.826423 3.18836L2.39191 1.62288V9.50781C2.39191 9.77037 2.60475 9.98321 2.86731 9.98321C3.12988 9.98321 3.34272 9.77037 3.34272 9.50781V1.6229L4.90821 3.18839C5.09706 3.37079 5.39801 3.36555 5.58041 3.17669C5.75829 2.99246 5.75829 2.7004 5.58035 2.51616Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<select
|
||||
className="text-sm font-medium"
|
||||
onChange={mediaFilterOnChange}
|
||||
value={mediaFilter}
|
||||
>
|
||||
<option value="all">All</option>
|
||||
<option value="photos">Photos</option>
|
||||
<option value="videos">Videos</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-[10px]"
|
||||
|
||||
@@ -216,6 +216,11 @@ const PhotoViewerPopup: React.FC<PhotoViewerPopupProps> = memo((props) => {
|
||||
dispatch(resetPopupSelect());
|
||||
}, [resetPopupSelect]);
|
||||
|
||||
const outterWrapperClick = (e: any) => {
|
||||
if (e.target.id !== "outer-wrapper") return;
|
||||
closePhotoViewer();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (file.metadata.isVideo) {
|
||||
getVideo();
|
||||
@@ -227,10 +232,7 @@ const PhotoViewerPopup: React.FC<PhotoViewerPopupProps> = memo((props) => {
|
||||
}, [file.metadata.isVideo, getVideo, cleanUpVideo]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-screen h-screen bg-black bg-opacity-80 absolute top-0 left-0 right-0 bottom-0 z-50 flex justify-center items-center flex-col"
|
||||
id="outer-wrapper"
|
||||
>
|
||||
<div className="w-screen h-screen bg-black bg-opacity-80 absolute top-0 left-0 right-0 bottom-0 z-50 flex justify-center items-center flex-col">
|
||||
{contextMenuState.selected && (
|
||||
<div onClick={clickStopPropagation}>
|
||||
<ContextMenu
|
||||
|
||||
@@ -14,7 +14,7 @@ const QuickAccess = memo(() => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="overflow-hidden"
|
||||
className="overflow-hidden select-none"
|
||||
style={isHome ? { display: "block" } : { display: "none" }}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-between mb-5">
|
||||
|
||||
@@ -4,12 +4,14 @@ import { memo, useMemo } from "react";
|
||||
import ContextMenu from "../ContextMenu/ContextMenu";
|
||||
import classNames from "classnames";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { getFileExtension } from "../../utils/files";
|
||||
import { getFileColor, getFileExtension } from "../../utils/files";
|
||||
import { useContextMenu } from "../../hooks/contextMenu";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAppSelector } from "../../hooks/store";
|
||||
import { resetSelected, setPopupSelect } from "../../reducers/selected";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import { useThumbnail } from "../../hooks/files";
|
||||
import CloseIcon from "../../icons/CloseIcon";
|
||||
|
||||
const RightSection = memo(() => {
|
||||
const selectedItem = useAppSelector((state) => state.selected.mainSection);
|
||||
@@ -77,10 +79,31 @@ const RightSection = memo(() => {
|
||||
navigate(`/folder-trash/${selectedItem.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const bannerBackgroundColor = useMemo(() => {
|
||||
if (selectedItem.file) {
|
||||
return getFileColor(selectedItem.file.filename);
|
||||
} else if (selectedItem.folder) {
|
||||
return "#3c85ee";
|
||||
} else {
|
||||
return "#3c85ee";
|
||||
}
|
||||
}, [selectedItem.file?.filename, selectedItem.folder?.name]);
|
||||
|
||||
const bannerText = useMemo(() => {
|
||||
if (selectedItem.file) {
|
||||
return getFileExtension(selectedItem.file.filename);
|
||||
} else if (selectedItem.folder) {
|
||||
return "Folder";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}, [selectedItem.file?.filename, selectedItem.folder?.name]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"!hidden desktopMode:!flex min-w-[260px] max-w-[260px] border-l border-gray-secondary p-6 bg-white right-0 justify-center relative mt-1.5",
|
||||
"!hidden desktopMode:!flex min-w-[260px] max-w-[260px] border-l border-gray-secondary bg-white right-0 justify-center relative mt-1.5",
|
||||
selectedItem.id === "" ? "flex justify-center items-center" : ""
|
||||
)}
|
||||
>
|
||||
@@ -94,86 +117,97 @@ const RightSection = memo(() => {
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-[210px]">
|
||||
<div className="w-full">
|
||||
<div className="flex flex-row">
|
||||
<div>
|
||||
{/* <div>
|
||||
<img
|
||||
className="flex w-auto max-w-full"
|
||||
src="/assets/typedetailed1.svg"
|
||||
alt="typedetailed1"
|
||||
/>
|
||||
</div> */}
|
||||
<div>
|
||||
{/* <img className="object-cover w-full" src={thumbnail} /> */}
|
||||
</div>
|
||||
<img
|
||||
className="w-[30px] h-[30px] ml-8 cursor-pointer absolute right-3"
|
||||
src="/images/close_icon.png"
|
||||
<div className="w-full h-16 flex items-center relative">
|
||||
<div
|
||||
className="opacity-40 w-full h-full absolute"
|
||||
style={{ background: bannerBackgroundColor }}
|
||||
></div>
|
||||
<p className="text-sm ml-6 z-10">{bannerText}</p>
|
||||
</div>
|
||||
<CloseIcon
|
||||
className="w-5 h-5 p-1 cursor-pointer absolute right-3 top-5 bg-white rounded-full shadow-lg z-10"
|
||||
onClick={reset}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="m-[20px_0]">
|
||||
<p className="m-0 text-[#212b36] text-[16px] font-bold max-h-[90px] overflow-hidden text-ellipsis block break-all">
|
||||
{formattedName}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Type
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file ? fileExtension : "Folder"}
|
||||
</span>
|
||||
<div className="p-6">
|
||||
<div className="mb-5">
|
||||
<p className="m-0 text-[#212b36] text-[16px] font-bold max-h-[90px] overflow-hidden text-ellipsis block break-all">
|
||||
{formattedName}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Size
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{fileSize}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Created
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{formattedDate}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Access
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file?.metadata.link ? "Public" : "Private"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-[15px] flex items-center">
|
||||
<a
|
||||
className="w-[80px] h-[40px] inline-flex items-center justify-center border border-[#3c85ee] rounded-[4px] text-[#3c85ee] text-[15px] font-medium no-underline animate cursor-pointer hover:bg-[#f6f5fd]"
|
||||
onClick={openItem}
|
||||
>
|
||||
Open
|
||||
</a>
|
||||
<div className="ml-[15px] px-[20px]">
|
||||
<a
|
||||
className="w-[40px] h-[40px] rounded-[4px] inline-flex items-center justify-center border border-[#919eab] text-[#919eab] no-underline animate cursor-pointer"
|
||||
// @ts-ignore
|
||||
onClick={onContextMenu}
|
||||
<div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Type
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file ? fileExtension : "Folder"}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<i className="fas fa-ellipsis-h" aria-hidden="true"></i>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Size
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{fileSize}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex mb-[7px] justify-start">
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Created
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{formattedDate}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex mb-[7px] justify-start"
|
||||
style={
|
||||
!selectedItem.file ? { display: "none" } : { display: "flex" }
|
||||
}
|
||||
>
|
||||
<span className="text-[#637381] text-[13px] font-normal mr-[35px] leading-[20px] min-w-[50px]">
|
||||
Access
|
||||
</span>
|
||||
<span className="text-[#212b36] text-[13px] font-normal leading-[20px]">
|
||||
{selectedItem.file?.metadata.link ? "Public" : "Private"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-[15px] flex items-center">
|
||||
<a
|
||||
className="w-[80px] h-[40px] inline-flex items-center justify-center border border-[#3c85ee] rounded-[4px] text-[#3c85ee] text-[15px] font-medium no-underline animate cursor-pointer hover:bg-[#f6f5fd]"
|
||||
onClick={openItem}
|
||||
>
|
||||
Open
|
||||
</a>
|
||||
<div className="ml-[15px] px-[20px]">
|
||||
<a
|
||||
className="w-[40px] h-[40px] rounded-[4px] inline-flex items-center justify-center border border-[#919eab] text-[#919eab] no-underline animate cursor-pointer"
|
||||
// @ts-ignore
|
||||
onClick={onContextMenu}
|
||||
>
|
||||
<i className="fas fa-ellipsis-h" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{contextMenuState.selected && (
|
||||
|
||||
@@ -37,13 +37,14 @@ const SearchBar = memo(() => {
|
||||
setDebouncedSearchText("");
|
||||
}, []);
|
||||
|
||||
const { wrapperRef } = useClickOutOfBounds(resetState);
|
||||
const outOfContainerClick = useCallback(() => {
|
||||
closeDrawer();
|
||||
}, []);
|
||||
|
||||
const { wrapperRef } = useClickOutOfBounds(outOfContainerClick);
|
||||
|
||||
// TODO: Fix any
|
||||
const onSearch = (e: any) => {
|
||||
e.preventDefault();
|
||||
setSearchText("");
|
||||
setDebouncedSearchText("");
|
||||
if (isMedia) {
|
||||
if (searchText.length) {
|
||||
navigate(`/search-media/${searchText}`);
|
||||
|
||||
@@ -10,10 +10,10 @@ const SettingsPageGeneral = () => {
|
||||
const fileListStyleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = e.target.value;
|
||||
setListViewStyle(value);
|
||||
if (value === "grid") {
|
||||
window.localStorage.setItem("grid-mode", "true");
|
||||
if (value === "list") {
|
||||
window.localStorage.setItem("list-mode", "true");
|
||||
} else {
|
||||
window.localStorage.removeItem("grid-mode");
|
||||
window.localStorage.removeItem("list-mode");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,8 +63,8 @@ const SettingsPageGeneral = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const gridModeLocalStorage = window.localStorage.getItem("grid-mode");
|
||||
const gridModeEnabled = gridModeLocalStorage === "true";
|
||||
const listModeLocalStorage = window.localStorage.getItem("list-mode");
|
||||
const listModeEnabled = listModeLocalStorage === "true";
|
||||
|
||||
const sortByLocalStorage = window.localStorage.getItem("sort-name");
|
||||
const sortByNameEnabled = sortByLocalStorage === "true";
|
||||
@@ -82,7 +82,7 @@ const SettingsPageGeneral = () => {
|
||||
);
|
||||
const loadThumbnailsDisabled = loadThumbnailsLocalStorage === "true";
|
||||
|
||||
setListViewStyle(gridModeEnabled ? "grid" : "list");
|
||||
setListViewStyle(listModeEnabled ? "list" : "grid");
|
||||
setSortBy(sortByNameEnabled ? "name" : "date");
|
||||
setOrderBy(orderByAscendingEnabled ? "ascending" : "descending");
|
||||
setDoubleClickFolders(doubleClickFoldersEnabled ? "enabled" : "disabled");
|
||||
@@ -102,8 +102,8 @@ const SettingsPageGeneral = () => {
|
||||
onChange={fileListStyleChange}
|
||||
className="text-primary"
|
||||
>
|
||||
<option value="list">List</option>
|
||||
<option value="grid">Grid</option>
|
||||
<option value="list">List</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="px-3 py-4 flex flex-row justify-between items-center border-b border-gray-secondary">
|
||||
|
||||
@@ -33,6 +33,7 @@ export const useFiles = (enabled = true) => {
|
||||
const params = useParams();
|
||||
// TODO: Remove any
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const mediaFilter = useAppSelector((state) => state.filter.mediaFilter);
|
||||
const { isTrash, isMedia } = useUtils();
|
||||
const limit = isMedia ? 100 : 50;
|
||||
const filesReactQuery: UseInfiniteQueryResult<FileInterface[]> =
|
||||
@@ -46,6 +47,7 @@ export const useFiles = (enabled = true) => {
|
||||
limit,
|
||||
trashMode: isTrash,
|
||||
mediaMode: isMedia,
|
||||
mediaFilter: mediaFilter,
|
||||
},
|
||||
],
|
||||
getFilesListAPI,
|
||||
|
||||
+5
-1
@@ -31,7 +31,11 @@ export const useUtils = () => {
|
||||
return location.pathname.includes("/folder/");
|
||||
}, [location.pathname]);
|
||||
|
||||
return { isHome, isTrash, isMedia, isSettings, isHomeFolder };
|
||||
const isSearch = useMemo(() => {
|
||||
return location.pathname.includes("/search/");
|
||||
}, [location.pathname]);
|
||||
|
||||
return { isHome, isTrash, isMedia, isSettings, isHomeFolder, isSearch };
|
||||
};
|
||||
|
||||
export const useClickOutOfBounds = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
const gridView = window.localStorage.getItem("grid-mode");
|
||||
const listView = window.localStorage.getItem("list-mode");
|
||||
|
||||
const sortBy = window.localStorage.getItem("name-mode")
|
||||
? window.localStorage.getItem("asc-mode")
|
||||
@@ -14,7 +14,8 @@ const initialState = {
|
||||
sortBy: sortBy,
|
||||
limit: 50,
|
||||
search: "",
|
||||
listView: !gridView,
|
||||
listView: listView === "true",
|
||||
mediaFilter: "all",
|
||||
};
|
||||
|
||||
const leftSectionSlice = createSlice({
|
||||
@@ -27,9 +28,13 @@ const leftSectionSlice = createSlice({
|
||||
setSortBy: (state, action: PayloadAction<string>) => {
|
||||
state.sortBy = action.payload;
|
||||
},
|
||||
setMediaFilter: (state, action: PayloadAction<string>) => {
|
||||
state.mediaFilter = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { toggleListView, setSortBy } = leftSectionSlice.actions;
|
||||
export const { toggleListView, setSortBy, setMediaFilter } =
|
||||
leftSectionSlice.actions;
|
||||
|
||||
export default leftSectionSlice.reducer;
|
||||
|
||||
Reference in New Issue
Block a user