diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-11-28 15:39:57 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-28 15:39:57 +0000 |
| commit | 2619f4cfefdf9264a7f4c3a8741493323fdde901 (patch) | |
| tree | 570264ff512525bfff7f67933bbea7b7c288b60e /apps/web/components/dashboard/sidebar/AllLists.tsx | |
| parent | 9ed338fe81a7f225fdffb0f09d0fa8fc6bcf815e (diff) | |
| download | karakeep-2619f4cfefdf9264a7f4c3a8741493323fdde901.tar.zst | |
fix: separate shared lists in the sidebar (#2180)
* fix: separate shared lists in the sidebar
* fix sub
* i18n
Diffstat (limited to 'apps/web/components/dashboard/sidebar/AllLists.tsx')
| -rw-r--r-- | apps/web/components/dashboard/sidebar/AllLists.tsx | 137 |
1 files changed, 130 insertions, 7 deletions
diff --git a/apps/web/components/dashboard/sidebar/AllLists.tsx b/apps/web/components/dashboard/sidebar/AllLists.tsx index 1cc3f3a5..f8b80cba 100644 --- a/apps/web/components/dashboard/sidebar/AllLists.tsx +++ b/apps/web/components/dashboard/sidebar/AllLists.tsx @@ -1,16 +1,24 @@ "use client"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import SidebarItem from "@/components/shared/sidebar/SidebarItem"; import { Button } from "@/components/ui/button"; -import { CollapsibleTriggerTriangle } from "@/components/ui/collapsible"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTriggerTriangle, +} from "@/components/ui/collapsible"; import { useTranslation } from "@/lib/i18n/client"; import { cn } from "@/lib/utils"; import { MoreHorizontal, Plus } from "lucide-react"; import type { ZBookmarkList } from "@karakeep/shared/types/lists"; +import { + augmentBookmarkListsWithInitialData, + useBookmarkLists, +} from "@karakeep/shared-react/hooks/lists"; import { ZBookmarkListTreeNode } from "@karakeep/shared/utils/listUtils"; import { CollapsibleBookmarkLists } from "../lists/CollapsibleBookmarkLists"; @@ -31,6 +39,36 @@ export default function AllLists({ const [selectedListId, setSelectedListId] = useState<string | null>(null); + // Fetch live lists data + const { data: listsData } = useBookmarkLists(undefined, { + initialData: { lists: initialData.lists }, + }); + const lists = augmentBookmarkListsWithInitialData( + listsData, + initialData.lists, + ); + + // Check if any shared list is currently being viewed + const isViewingSharedList = useMemo(() => { + return lists.data.some( + (list) => list.userRole !== "owner" && pathName.includes(list.id), + ); + }, [lists.data, pathName]); + + // Check if there are any shared lists + const hasSharedLists = useMemo(() => { + return lists.data.some((list) => list.userRole !== "owner"); + }, [lists.data]); + + const [sharedListsOpen, setSharedListsOpen] = useState(isViewingSharedList); + + // Auto-open shared lists if viewing one + useEffect(() => { + if (isViewingSharedList && !sharedListsOpen) { + setSharedListsOpen(true); + } + }, [isViewingSharedList, sharedListsOpen]); + return ( <ul className="max-h-full gap-y-2 overflow-auto text-sm"> <li className="flex justify-between pb-3"> @@ -60,10 +98,13 @@ export default function AllLists({ linkClassName="py-0.5" className="px-0.5" /> + + {/* Owned Lists */} <CollapsibleBookmarkLists - initialData={initialData.lists} + listsData={lists} + filter={(node) => node.item.userRole === "owner"} isOpenFunc={isNodeOpen} - render={({ item: node, level, open, numBookmarks }) => ( + render={({ node, level, open, numBookmarks }) => ( <SidebarItem collapseButton={ node.children.length > 0 && ( @@ -83,8 +124,8 @@ export default function AllLists({ className="group px-0.5" right={ <ListOptions - onOpenChange={(open) => { - if (open) { + onOpenChange={(isOpen) => { + if (isOpen) { setSelectedListId(node.item.id); } else { setSelectedListId(null); @@ -101,7 +142,6 @@ export default function AllLists({ : "opacity-0", )} /> - <span className={cn( "px-2.5 text-xs font-light text-muted-foreground opacity-100 transition-opacity duration-100 group-hover:opacity-0", @@ -121,6 +161,89 @@ export default function AllLists({ /> )} /> + + {/* Shared Lists */} + {hasSharedLists && ( + <Collapsible open={sharedListsOpen} onOpenChange={setSharedListsOpen}> + <SidebarItem + collapseButton={ + <CollapsibleTriggerTriangle + className="absolute left-0.5 top-1/2 size-2 -translate-y-1/2" + open={sharedListsOpen} + /> + } + logo={<span className="text-lg">👥</span>} + name={t("lists.shared_lists")} + path="#" + linkClassName="py-0.5" + className="px-0.5" + /> + <CollapsibleContent> + <CollapsibleBookmarkLists + listsData={lists} + filter={(node) => node.item.userRole !== "owner"} + isOpenFunc={isNodeOpen} + indentOffset={1} + render={({ node, level, open, numBookmarks }) => ( + <SidebarItem + collapseButton={ + node.children.length > 0 && ( + <CollapsibleTriggerTriangle + className="absolute left-0.5 top-1/2 size-2 -translate-y-1/2" + open={open} + /> + ) + } + logo={ + <span className="flex"> + <span className="text-lg"> {node.item.icon}</span> + </span> + } + name={node.item.name} + path={`/dashboard/lists/${node.item.id}`} + className="group px-0.5" + right={ + <ListOptions + onOpenChange={(isOpen) => { + if (isOpen) { + setSelectedListId(node.item.id); + } else { + setSelectedListId(null); + } + }} + list={node.item} + > + <Button size="none" variant="ghost" className="relative"> + <MoreHorizontal + className={cn( + "absolute inset-0 m-auto size-4 opacity-0 transition-opacity duration-100 group-hover:opacity-100", + selectedListId == node.item.id + ? "opacity-100" + : "opacity-0", + )} + /> + <span + className={cn( + "px-2.5 text-xs font-light text-muted-foreground opacity-100 transition-opacity duration-100 group-hover:opacity-0", + selectedListId == node.item.id || + numBookmarks === undefined + ? "opacity-0" + : "opacity-100", + )} + > + {numBookmarks} + </span> + </Button> + </ListOptions> + } + linkClassName="py-0.5" + style={{ marginLeft: `${level * 1}rem` }} + /> + )} + /> + </CollapsibleContent> + </Collapsible> + )} </ul> ); } |
