diff --git a/src/components/Filters.tsx b/src/components/Filters.tsx index 24bc707..8f5e72c 100644 --- a/src/components/Filters.tsx +++ b/src/components/Filters.tsx @@ -51,9 +51,15 @@ export function useFilterState(): useFilterStateReturn { export const FilterHeading = ({ disclosure, indicator, + title = "Filters", + icon = , + ...props }: { disclosure: UseDisclosureReturn; indicator?: number; + title?: string; + icon?: React.ReactElement; + [key: string]: any; }) => ( - Filters + {title} {indicator ? ( @@ -75,7 +82,7 @@ export const FilterHeading = ({ ) : null} - {disclosure.isOpen ? : } + {disclosure.isOpen ? : icon} ); diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 122fe7c..047e9dc 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -16,8 +16,9 @@ import { Switch, VStack, IconButton, + StepSeparator } from "@chakra-ui/react"; -import { IoDocumentAttach, IoPause, IoPlay } from "react-icons/io5"; +import { IoDocumentAttach, IoPause, IoPlay, IoSwapVertical } from "react-icons/io5"; import { useMutation, useQuery } from "react-query"; import { TorrClient } from "../utils/TorrClient"; import { useEffect, useMemo, useRef, useState } from "react"; @@ -35,6 +36,19 @@ import { useFontSizeContext } from "../components/FontSizeProvider"; import { List, WindowScroller } from "react-virtualized"; +type SortKey = + | "added_on" + | "name" + | "size" + | "progress" + | "dlspeed" + | "upspeed"; +type SortDirection = "asc" | "desc"; +interface SortConfig { + key: SortKey; + direction: SortDirection; +} + const Home = () => { const { mutate: resumeAll } = useMutation("resumeAll", TorrClient.resumeAll); @@ -135,6 +149,7 @@ const Home = () => { const isLarge = useIsLargeScreen(); const filterDisclosure = useDisclosure(); + const sortDisclosure = useDisclosure(); const [filterSearch, setFilterSearch] = useLocalStorage( "home-filter-search", "" @@ -147,6 +162,10 @@ const Home = () => { "home-filter-status", "Show All" ); + const [sortConfig, setSortConfig] = useLocalStorage( + "home-sort-config", + { key: "added_on", direction: "desc" } + ); const resetFilters = () => { setFilterStatus("Show All"); @@ -172,7 +191,26 @@ const Home = () => { } return Object.entries(torrentsTx) - ?.sort((a, b) => b[1]?.added_on - a[1]?.added_on) + ?.sort(([, a], [, b]) => { + if (!a || !b) return 0; + const aVal = a[sortConfig.key as keyof TorrTorrentInfo]; + const bVal = b[sortConfig.key as keyof TorrTorrentInfo]; + + if (aVal === bVal) return 0; + if (aVal === undefined || aVal === null) + return sortConfig.direction === "asc" ? -1 : 1; + if (bVal === undefined || bVal === null) + return sortConfig.direction === "asc" ? 1 : -1; + + let compare = 0; + if (typeof aVal === "string" && typeof bVal === "string") { + compare = aVal.localeCompare(bVal); + } else if (typeof aVal === "number" && typeof bVal === "number") { + compare = aVal - bVal; + } + + return sortConfig.direction === "asc" ? compare : -compare; + }) ?.filter(([hash]) => !removedTorrs.includes(hash)) ?.filter(([hash, torr]) => filterCategory !== "Show All" ? torr.category === filterCategory : true @@ -181,7 +219,14 @@ const Home = () => { filterStatus !== "Show All" ? torr.state === filterStatus : true ) ?.filter(([hash, torr]) => torr.name.includes(filterSearch)); - }, [torrentsTx, removedTorrs, filterCategory, filterStatus, filterSearch]); + }, [ + torrentsTx, + removedTorrs, + filterCategory, + filterStatus, + filterSearch, + sortConfig, + ]); const Categories = useMemo(() => { return Object.values(categories || {}).map((c) => ({ @@ -384,10 +429,32 @@ const Home = () => { - + + { + if (sortDisclosure.isOpen) { + sortDisclosure.onClose(); + } + filterDisclosure.onToggle(); + }} + roundedRight={0} + /> +
+ } + onClick={() => { + if (filterDisclosure.isOpen) { + filterDisclosure.onClose(); + } + sortDisclosure.onToggle(); + }} + roundedLeft={0} + /> +
{filterDisclosure.isOpen && ( @@ -425,6 +492,44 @@ const Home = () => { )} + {sortDisclosure.isOpen && ( + + + Sort by + + + + Direction + + + + )}
@@ -501,4 +606,4 @@ const Home = () => { ); }; -export default Home; +export default Home; \ No newline at end of file