From 0a319200aea159bb6f212608c20132fdedfacf43 Mon Sep 17 00:00:00 2001
From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com>
Date: Sat, 18 Dec 2021 13:34:01 +0200
Subject: [PATCH] Less jank dragging UI
---
app/components/Draggable.tsx | 35 +++++++++
.../to/$organization.$tournament/seeds.tsx | 73 +++++++++++--------
app/styles/global.css | 1 +
app/styles/tournament-seeds.css | 5 ++
4 files changed, 82 insertions(+), 32 deletions(-)
create mode 100644 app/components/Draggable.tsx
diff --git a/app/components/Draggable.tsx b/app/components/Draggable.tsx
new file mode 100644
index 000000000..0cffa773c
--- /dev/null
+++ b/app/components/Draggable.tsx
@@ -0,0 +1,35 @@
+import { useSortable } from "@dnd-kit/sortable";
+import { CSS } from "@dnd-kit/utilities";
+import * as React from "react";
+
+export function Draggable({
+ id,
+ disabled,
+ liClassName,
+ children,
+}: {
+ id: string;
+ disabled: boolean;
+ liClassName: string;
+ children: React.ReactNode;
+}) {
+ const { attributes, listeners, setNodeRef, transform, transition } =
+ useSortable({ id, disabled });
+
+ const style = {
+ transform: CSS.Transform.toString(transform),
+ transition,
+ };
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/routes/to/$organization.$tournament/seeds.tsx b/app/routes/to/$organization.$tournament/seeds.tsx
index c65b3071e..9762ff6eb 100644
--- a/app/routes/to/$organization.$tournament/seeds.tsx
+++ b/app/routes/to/$organization.$tournament/seeds.tsx
@@ -1,6 +1,7 @@
import {
closestCenter,
DndContext,
+ DragOverlay,
KeyboardSensor,
PointerSensor,
useSensor,
@@ -10,28 +11,27 @@ import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
- useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
-import { CSS } from "@dnd-kit/utilities";
import classNames from "classnames";
import * as React from "react";
-import { useFetcher, useMatches } from "remix";
import type { LinksFunction } from "remix";
+import { useFetcher, useMatches } from "remix";
+import invariant from "tiny-invariant";
import { Alert } from "~/components/Alert";
import { Button } from "~/components/Button";
+import { Draggable } from "~/components/Draggable";
import { TOURNAMENT_TEAM_ROSTER_MIN_SIZE } from "~/constants";
import { checkInHasStarted } from "~/core/tournament/utils";
import type { FindTournamentByNameForUrlI } from "~/services/tournament";
+import seedsStylesUrl from "~/styles/tournament-seeds.css";
import type { Unpacked } from "~/utils";
import { useTimeoutState } from "~/utils/hooks";
-import seedsStylesUrl from "~/styles/tournament-seeds.css";
export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: seedsStylesUrl }];
};
-// TODO: https://docs.dndkit.com/presets/sortable#drag-overlay
// TODO: what if returns error? check other APIs too -> add Cypress test
// TODO: error if not admin
export default function SeedsTab() {
@@ -40,6 +40,9 @@ export default function SeedsTab() {
const { id, teams, checkInStartTime } =
parentRoute.data as FindTournamentByNameForUrlI;
const [teamOrder, setTeamOrder] = React.useState(teams.map((t) => t.id));
+ const [activeTeam, setActiveTeam] = React.useState | null>(null);
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
@@ -73,11 +76,18 @@ export default function SeedsTab() {
id="team-seed-sorter"
sensors={sensors}
collisionDetection={closestCenter}
- onDragStart={() => null}
+ onDragStart={(event) => {
+ const newActiveTeam = teamsSorted.find(
+ (t) => t.id === event.active.id
+ );
+ invariant(newActiveTeam, "newActiveTeam is undefined");
+ setActiveTeam(newActiveTeam);
+ }}
onDragEnd={(event) => {
const { active, over } = event;
if (!over) return;
+ setActiveTeam(null);
if (active.id !== over.id) {
setTeamOrder((teamIds) => {
const oldIndex = teamIds.indexOf(active.id);
@@ -93,14 +103,31 @@ export default function SeedsTab() {
strategy={verticalListSortingStrategy}
>
{teamsSorted.map((team, i) => (
-
+ liClassName={classNames(
+ "tournament__seeds__teams-list-row",
+ "sortable",
+ {
+ disabled: seedsFetcher.state !== "idle",
+ "visibility-hidden": activeTeam?.id === team.id,
+ }
+ )}
+ >
+
+
))}
+
+
+ {activeTeam && (
+
+
+
+ )}
+
>
@@ -164,36 +191,18 @@ function SeedAlert({
);
}
-function SortableRow({
+function RowContents({
team,
seed,
- disabled,
}: {
team: Unpacked;
- seed: number;
- disabled: boolean;
+ seed?: number;
}) {
const [, parentRoute] = useMatches();
const { checkInStartTime } = parentRoute.data as FindTournamentByNameForUrlI;
- const { attributes, listeners, setNodeRef, transform, transition } =
- useSortable({ id: team.id, disabled });
-
- const style = {
- transform: CSS.Transform.toString(transform),
- transition,
- };
-
return (
-
+ <>
{seed}
{team.name}
@@ -222,7 +231,7 @@ function SortableRow({
>
{team.members.length}
-
+ >
);
}
diff --git a/app/styles/global.css b/app/styles/global.css
index e8e4e0a9f..b08b5d1fd 100644
--- a/app/styles/global.css
+++ b/app/styles/global.css
@@ -1,6 +1,7 @@
:root {
--bg: hsl(237.3deg 42.3% 30.6%);
--bg-lighter: hsl(237.3deg 42.3% 35.6%);
+ --bg-lighter-transparent: hsla(237.3deg 42.3% 35.6% / 50%);
--border: hsl(237.3deg 42.3% 45.6%);
--text: rgb(255 255 255 / 95%);
--text-lighter: rgb(255 255 255 / 55%);
diff --git a/app/styles/tournament-seeds.css b/app/styles/tournament-seeds.css
index 20eb3cdd4..d11966fe5 100644
--- a/app/styles/tournament-seeds.css
+++ b/app/styles/tournament-seeds.css
@@ -33,7 +33,12 @@
}
.tournament__seeds__teams-list-row.sortable:hover:not(.disabled) {
+ background-color: var(--bg-lighter-transparent);
+}
+
+.tournament__seeds__teams-list-row.active {
background-color: var(--bg-lighter);
+ cursor: grabbing;
}
.tournament__seeds__teams-list-row.sortable:active:not(.disabled) {