diff options
| author | kamtschatka <simon.schatka@gmx.at> | 2024-07-01 13:59:10 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-01 12:59:10 +0100 |
| commit | 9cd617055b7878048120eebd58dc2e05a9cbdfca (patch) | |
| tree | 4c80908640bb6b92e355d027ed64fce26fac2454 /apps/web/components/dashboard | |
| parent | 9883c6bcd18c2ca1fda7d83e465a0bf9cf45510d (diff) | |
| download | karakeep-9cd617055b7878048120eebd58dc2e05a9cbdfca.tar.zst | |
refactor: drag and drop improvements (#264)
* [Feature request] Drag and Drop Items to Lists #123
reworked the drag and drop mechanism to still have change detection, but not so much that it has a huge overhead
Changed the layout a bit to allow proper drag/drop of elements from the main section to the sidebar
Added the possibility to drag/drop bookmarks onto lists
* [Feature request] Drag and Drop Items to Lists #123
Removed the changes to allow dragging&dropping bookmarks
Diffstat (limited to 'apps/web/components/dashboard')
| -rw-r--r-- | apps/web/components/dashboard/tags/AllTagsView.tsx | 77 | ||||
| -rw-r--r-- | apps/web/components/dashboard/tags/TagPill.tsx | 96 |
2 files changed, 86 insertions, 87 deletions
diff --git a/apps/web/components/dashboard/tags/AllTagsView.tsx b/apps/web/components/dashboard/tags/AllTagsView.tsx index ac139e23..7b81ed72 100644 --- a/apps/web/components/dashboard/tags/AllTagsView.tsx +++ b/apps/web/components/dashboard/tags/AllTagsView.tsx @@ -13,16 +13,11 @@ import InfoTooltip from "@/components/ui/info-tooltip"; import { Separator } from "@/components/ui/separator"; import { Toggle } from "@/components/ui/toggle"; import { toast } from "@/components/ui/use-toast"; -import { useDragAndDrop } from "@/lib/drag-and-drop"; import { api } from "@/lib/trpc"; import { ArrowDownAZ, Combine } from "lucide-react"; -import Draggable from "react-draggable"; import type { ZGetTagResponse } from "@hoarder/shared/types/tags"; -import { - useDeleteUnusedTags, - useMergeTag, -} from "@hoarder/shared-react/hooks/tags"; +import { useDeleteUnusedTags } from "@hoarder/shared-react/hooks/tags"; import { TagPill } from "./TagPill"; @@ -79,17 +74,6 @@ export default function AllTagsView({ const [draggingEnabled, setDraggingEnabled] = React.useState(false); const [sortByName, setSortByName] = React.useState(false); - const { handleDragStart, handleDragEnd } = useDragAndDrop( - "data-id", - "data-id", - (dragSourceId: string, dragTargetId: string) => { - mergeTag({ - fromTagIds: [dragSourceId], - intoTagId: dragTargetId, - }); - }, - ); - function toggleSortByName(): void { setSortByName(!sortByName); } @@ -98,40 +82,9 @@ export default function AllTagsView({ setDraggingEnabled(!draggingEnabled); } - const { mutate: mergeTag } = useMergeTag({ - onSuccess: () => { - toast({ - description: "Tags have been merged!", - }); - }, - onError: (e) => { - if (e.data?.code == "BAD_REQUEST") { - if (e.data.zodError) { - toast({ - variant: "destructive", - description: Object.values(e.data.zodError.fieldErrors) - .flat() - .join("\n"), - }); - } else { - toast({ - variant: "destructive", - description: e.message, - }); - } - } else { - toast({ - variant: "destructive", - title: "Something went wrong", - }); - } - }, - }); - const { data } = api.tags.list.useQuery(undefined, { initialData: { tags: initialData }, }); - // Sort tags by usage desc const allTags = data.tags.sort(sortByName ? byNameSorter : byUsageSorter); @@ -145,21 +98,13 @@ export default function AllTagsView({ tagPill = ( <div className="flex flex-wrap gap-3"> {tags.map((t) => ( - <Draggable + <TagPill key={t.id} - axis="both" - onStart={handleDragStart} - onStop={handleDragEnd} - disabled={!draggingEnabled} - defaultClassNameDragging={ - "position-relative z-10 pointer-events-none" - } - position={{ x: 0, y: 0 }} - > - <div className="cursor-grab" data-id={t.id}> - <TagPill id={t.id} name={t.name} count={t.count} /> - </div> - </Draggable> + id={t.id} + name={t.name} + count={t.count} + isDraggable={draggingEnabled} + /> ))} </div> ); @@ -173,6 +118,7 @@ export default function AllTagsView({ <div className="flex justify-end gap-x-2"> <Toggle variant="outline" + aria-label="Toggle bold" pressed={draggingEnabled} onPressedChange={toggleDraggingEnabled} > @@ -184,6 +130,7 @@ export default function AllTagsView({ </Toggle> <Toggle variant="outline" + aria-label="Toggle bold" pressed={sortByName} onPressedChange={toggleSortByName} > @@ -196,22 +143,16 @@ export default function AllTagsView({ <p>Tags that were attached at least once by you</p> </InfoTooltip> </span> - {tagsToPill(humanTags)} - <Separator /> - <span className="flex items-center gap-2"> <p className="text-lg">AI Tags</p> <InfoTooltip size={15} className="my-auto" variant="explain"> <p>Tags that were only attached automatically (by AI)</p> </InfoTooltip> </span> - {tagsToPill(aiTags)} - <Separator /> - <span className="flex items-center gap-2"> <p className="text-lg">Unused Tags</p> <InfoTooltip size={15} className="my-auto" variant="explain"> diff --git a/apps/web/components/dashboard/tags/TagPill.tsx b/apps/web/components/dashboard/tags/TagPill.tsx index f1c99d70..88b88b52 100644 --- a/apps/web/components/dashboard/tags/TagPill.tsx +++ b/apps/web/components/dashboard/tags/TagPill.tsx @@ -1,7 +1,13 @@ +import React from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; +import { toast } from "@/components/ui/use-toast"; +import { useDragAndDrop } from "@/lib/drag-and-drop"; import { X } from "lucide-react"; +import Draggable from "react-draggable"; + +import { useMergeTag } from "@hoarder/shared-react/hooks/tags"; import DeleteTagConfirmationDialog from "./DeleteTagConfirmationDialog"; @@ -9,32 +15,84 @@ export function TagPill({ id, name, count, + isDraggable, }: { id: string; name: string; count: number; + isDraggable: boolean; }) { - return ( - <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" + const { mutate: mergeTag } = useMergeTag({ + onSuccess: () => { + toast({ + description: "Tags have been merged!", + }); + }, + onError: (e) => { + if (e.data?.code == "BAD_REQUEST") { + if (e.data.zodError) { + toast({ + variant: "destructive", + description: Object.values(e.data.zodError.fieldErrors) + .flat() + .join("\n"), + }); + } else { + toast({ + variant: "destructive", + description: e.message, + }); } - href={`/dashboard/tags/${id}`} - data-id={id} - > - {name} <Separator orientation="vertical" /> {count} - </Link> + } else { + toast({ + variant: "destructive", + title: "Something went wrong", + }); + } + }, + }); + + const dragAndDropFunction = useDragAndDrop( + "data-id", + (dragTargetId: string) => { + mergeTag({ + fromTagIds: [id], + intoTagId: dragTargetId, + }); + }, + ); - <DeleteTagConfirmationDialog tag={{ name, id }}> - <Button - size="none" - variant="secondary" - className="-translate-1/2 absolute -right-1 -top-1 hidden rounded-full group-hover:block" + return ( + <Draggable + key={id} + axis="both" + onStart={dragAndDropFunction.handleDragStart} + onStop={dragAndDropFunction.handleDragEnd} + disabled={!isDraggable} + 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} > - <X className="size-3" /> - </Button> - </DeleteTagConfirmationDialog> - </div> + {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> + </Draggable> ); } |
