From e0999f701cd1834c3d940113cd8dd5247c5fe95f Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Fri, 19 Apr 2024 00:09:27 +0100 Subject: feature: Nested lists (#110). Fixes #62 * feature: Add support for nested lists * prevent moving the parent to a subtree --- .../dashboard/lists/CollapsibleBookmarkLists.tsx | 111 +++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 apps/web/components/dashboard/lists/CollapsibleBookmarkLists.tsx (limited to 'apps/web/components/dashboard/lists/CollapsibleBookmarkLists.tsx') diff --git a/apps/web/components/dashboard/lists/CollapsibleBookmarkLists.tsx b/apps/web/components/dashboard/lists/CollapsibleBookmarkLists.tsx new file mode 100644 index 00000000..da1b7408 --- /dev/null +++ b/apps/web/components/dashboard/lists/CollapsibleBookmarkLists.tsx @@ -0,0 +1,111 @@ +import { useEffect, useState } from "react"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; +import { FullPageSpinner } from "@/components/ui/full-page-spinner"; + +import { + augmentBookmarkListsWithInitialData, + useBookmarkLists, +} from "@hoarder/shared-react/hooks/lists"; +import { ZBookmarkList } from "@hoarder/shared/types/lists"; +import { ZBookmarkListTreeNode } from "@hoarder/shared/utils/listUtils"; + +type RenderFunc = (params: { + item: ZBookmarkListTreeNode; + level: number; + open: boolean; +}) => React.ReactNode; + +type IsOpenFunc = (list: ZBookmarkListTreeNode) => boolean; + +function ListItem({ + node, + render, + level, + className, + isOpenFunc, +}: { + node: ZBookmarkListTreeNode; + render: RenderFunc; + isOpenFunc: IsOpenFunc; + level: number; + className?: string; +}) { + // Not the most efficient way to do this, but it works for now + const isAnyChildOpen = ( + node: ZBookmarkListTreeNode, + isOpenFunc: IsOpenFunc, + ): boolean => { + if (isOpenFunc(node)) { + return true; + } + return node.children.some((l) => isAnyChildOpen(l, isOpenFunc)); + }; + const [open, setOpen] = useState(false); + useEffect(() => { + setOpen((curr) => curr || isAnyChildOpen(node, isOpenFunc)); + }, [node, isOpenFunc]); + + return ( + + {render({ + item: node, + level, + open, + })} + + {node.children.map((l) => ( + + ))} + + + ); +} + +export function CollapsibleBookmarkLists({ + render, + initialData, + className, + isOpenFunc, +}: { + initialData?: ZBookmarkList[]; + render: RenderFunc; + isOpenFunc?: IsOpenFunc; + className?: string; +}) { + let { data } = useBookmarkLists(undefined, { + initialData: initialData ? { lists: initialData } : undefined, + }); + + // TODO: This seems to be a bug in react query + if (initialData) { + data = augmentBookmarkListsWithInitialData(data, initialData); + } + + if (!data) { + return ; + } + + const { root } = data; + + return ( +
+ {Object.values(root).map((l) => ( + false)} + /> + ))} +
+ ); +} -- cgit v1.2.3-70-g09d2