diff options
| author | kamtschatka <simon.schatka@gmx.at> | 2024-10-13 14:01:19 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-13 13:01:19 +0100 |
| commit | 4791a534b2561071a01708775b23408f78d56dc8 (patch) | |
| tree | 8e56ab2601fbaf946aa41bce999eb94e492a401a /apps | |
| parent | de9cf0a45227da9d33feabe9c51a71845dad6763 (diff) | |
| download | karakeep-4791a534b2561071a01708775b23408f78d56dc8.tar.zst | |
fix(web): Fix slowness in loading the all tags UI. Fixes #382 (#390)
* long delay when selecting tags in UI #382
improved performance by not handling hover in css
also rendering the draggable div only if draggable mode is active
* updated the code to reuse the DeleteTagConfirmationDialog to improve performance and fix the tag deletion
* some fixes
---------
Co-authored-by: MohamedBassem <me@mbassem.com>
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/components/dashboard/tags/AllTagsView.tsx | 27 | ||||
| -rw-r--r-- | apps/web/components/dashboard/tags/DeleteTagConfirmationDialog.tsx | 6 | ||||
| -rw-r--r-- | apps/web/components/dashboard/tags/TagPill.tsx | 66 |
3 files changed, 70 insertions, 29 deletions
diff --git a/apps/web/components/dashboard/tags/AllTagsView.tsx b/apps/web/components/dashboard/tags/AllTagsView.tsx index 7b81ed72..f6a42ef2 100644 --- a/apps/web/components/dashboard/tags/AllTagsView.tsx +++ b/apps/web/components/dashboard/tags/AllTagsView.tsx @@ -19,6 +19,7 @@ import { ArrowDownAZ, Combine } from "lucide-react"; import type { ZGetTagResponse } from "@hoarder/shared/types/tags"; import { useDeleteUnusedTags } from "@hoarder/shared-react/hooks/tags"; +import DeleteTagConfirmationDialog from "./DeleteTagConfirmationDialog"; import { TagPill } from "./TagPill"; function DeleteAllUnusedTags({ numUnusedTags }: { numUnusedTags: number }) { @@ -71,9 +72,22 @@ export default function AllTagsView({ }: { initialData: ZGetTagResponse[]; }) { + interface Tag { + id: string; + name: string; + } + const [draggingEnabled, setDraggingEnabled] = React.useState(false); const [sortByName, setSortByName] = React.useState(false); + const [isDialogOpen, setIsDialogOpen] = React.useState(false); + const [selectedTag, setSelectedTag] = React.useState<Tag | null>(null); + + const handleOpenDialog = (tag: Tag) => { + setSelectedTag(tag); + setIsDialogOpen(true); + }; + function toggleSortByName(): void { setSortByName(!sortByName); } @@ -104,6 +118,7 @@ export default function AllTagsView({ name={t.name} count={t.count} isDraggable={draggingEnabled} + onOpenDialog={handleOpenDialog} /> ))} </div> @@ -115,6 +130,18 @@ export default function AllTagsView({ }; return ( <> + {selectedTag && ( + <DeleteTagConfirmationDialog + tag={selectedTag} + open={isDialogOpen} + setOpen={(o) => { + if (!o) { + setSelectedTag(null); + } + setIsDialogOpen(o); + }} + /> + )} <div className="flex justify-end gap-x-2"> <Toggle variant="outline" diff --git a/apps/web/components/dashboard/tags/DeleteTagConfirmationDialog.tsx b/apps/web/components/dashboard/tags/DeleteTagConfirmationDialog.tsx index 7021b715..998ac9b8 100644 --- a/apps/web/components/dashboard/tags/DeleteTagConfirmationDialog.tsx +++ b/apps/web/components/dashboard/tags/DeleteTagConfirmationDialog.tsx @@ -7,12 +7,10 @@ import { useDeleteTag } from "@hoarder/shared-react/hooks/tags"; export default function DeleteTagConfirmationDialog({ tag, - children, open, setOpen, }: { tag: { id: string; name: string }; - children?: React.ReactNode; open?: boolean; setOpen?: (v: boolean) => void; }) { @@ -55,8 +53,6 @@ export default function DeleteTagConfirmationDialog({ Delete </ActionButton> )} - > - {children} - </ActionConfirmingDialog> + /> ); } diff --git a/apps/web/components/dashboard/tags/TagPill.tsx b/apps/web/components/dashboard/tags/TagPill.tsx index 88b88b52..ff17f224 100644 --- a/apps/web/components/dashboard/tags/TagPill.tsx +++ b/apps/web/components/dashboard/tags/TagPill.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; @@ -9,19 +9,24 @@ import Draggable from "react-draggable"; import { useMergeTag } from "@hoarder/shared-react/hooks/tags"; -import DeleteTagConfirmationDialog from "./DeleteTagConfirmationDialog"; - export function TagPill({ id, name, count, isDraggable, + onOpenDialog, }: { id: string; name: string; count: number; isDraggable: boolean; + onOpenDialog: (tag: { id: string; name: string }) => void; }) { + const [isHovered, setIsHovered] = useState(false); + + const handleMouseOver = () => setIsHovered(true); + const handleMouseOut = () => setIsHovered(false); + const { mutate: mergeTag } = useMergeTag({ onSuccess: () => { toast({ @@ -62,6 +67,39 @@ export function TagPill({ }, ); + const pill = ( + <div + className="group relative flex" + onMouseOver={handleMouseOver} + onFocus={handleMouseOver} + onMouseOut={handleMouseOut} + onBlur={handleMouseOut} + > + <Link + className={ + "flex gap-2 rounded-md border border-border bg-background px-2 py-1 text-foreground hover:bg-foreground hover:text-background" + } + href={`/dashboard/tags/${id}`} + data-id={id} + > + {name} <Separator orientation="vertical" /> {count} + </Link> + + {isHovered && !isDraggable && ( + <Button + size="none" + variant="secondary" + className="-translate-1/2 absolute -right-1 -top-1 hidden rounded-full group-hover:block" + onClick={() => onOpenDialog({ id, name })} + > + <X className="size-3" /> + </Button> + )} + </div> + ); + if (!isDraggable) { + return pill; + } return ( <Draggable key={id} @@ -72,27 +110,7 @@ export function TagPill({ defaultClassNameDragging={"position-relative z-10 pointer-events-none"} position={{ x: 0, y: 0 }} > - <div className="group relative flex"> - <Link - className={ - "flex gap-2 rounded-md border border-border bg-background px-2 py-1 text-foreground hover:bg-foreground hover:text-background" - } - href={`/dashboard/tags/${id}`} - data-id={id} - > - {name} <Separator orientation="vertical" /> {count} - </Link> - - <DeleteTagConfirmationDialog tag={{ name, id }}> - <Button - size="none" - variant="secondary" - className="-translate-1/2 absolute -right-1 -top-1 hidden rounded-full group-hover:block" - > - <X className="size-3" /> - </Button> - </DeleteTagConfirmationDialog> - </div> + {pill} </Draggable> ); } |
