aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/dashboard
diff options
context:
space:
mode:
authorkamtschatka <simon.schatka@gmx.at>2024-07-01 13:59:10 +0200
committerGitHub <noreply@github.com>2024-07-01 12:59:10 +0100
commit9cd617055b7878048120eebd58dc2e05a9cbdfca (patch)
tree4c80908640bb6b92e355d027ed64fce26fac2454 /apps/web/components/dashboard
parent9883c6bcd18c2ca1fda7d83e465a0bf9cf45510d (diff)
downloadkarakeep-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.tsx77
-rw-r--r--apps/web/components/dashboard/tags/TagPill.tsx96
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>
);
}