diff --git a/src/lib/dnd.ts b/src/lib/dnd.ts new file mode 100644 index 00000000..9f8f1eb2 --- /dev/null +++ b/src/lib/dnd.ts @@ -0,0 +1,56 @@ +import { + Draggable as rbdDraggable, + DraggableProps as rbdDraggableProps, + DraggableProvided as rbdDraggableProvided, + DraggableProvidedDraggableProps as rbdDraggableProvidedDraggableProps, + DraggableProvidedDragHandleProps as rbdDraggableProvidedDragHandleProps, + DraggableRubric, + DraggableStateSnapshot, + Droppable as rbdDroppable, + DroppableProps, + DroppableProvided, + DroppableStateSnapshot, +} from "react-beautiful-dnd"; + +export type DraggableProvidedDraggableProps = Omit< + rbdDraggableProvidedDraggableProps, + "style" | "onTransitionEnd" +> & { + style?: string; + onTransitionEnd?: JSX.TransitionEventHandler; +}; + +export type DraggableProvidedDragHandleProps = Omit< + rbdDraggableProvidedDragHandleProps, + "onDragStart" +> & { + onDragStart?: JSX.DragEventHandler; +}; + +export type DraggableProvided = rbdDraggableProvided & { + draggableProps: DraggableProvidedDraggableProps; + dragHandleProps?: DraggableProvidedDragHandleProps | undefined; +}; + +export type DraggableChildrenFn = ( + provided: DraggableProvided, + snapshot: DraggableStateSnapshot, + rubric: DraggableRubric, +) => JSX.Element; + +export type DraggableProps = Omit & { + children: DraggableChildrenFn; +}; + +export const Draggable = rbdDraggable as unknown as ( + props: DraggableProps, +) => JSX.Element; + +export const Droppable = rbdDroppable as unknown as ( + props: Omit & { + children( + provided: DroppableProvided, + snapshot: DroppableStateSnapshot, + ): JSX.Element; + }, +) => JSX.Element; diff --git a/src/pages/settings/server/Categories.tsx b/src/pages/settings/server/Categories.tsx index 96e2c88d..f3dcd920 100644 --- a/src/pages/settings/server/Categories.tsx +++ b/src/pages/settings/server/Categories.tsx @@ -1,7 +1,6 @@ -import { Filter, Plus, X } from "@styled-icons/boxicons-regular"; -import isEqual from "lodash.isequal"; +import { Plus, X } from "@styled-icons/boxicons-regular"; import { observer } from "mobx-react-lite"; -import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; +import { DragDropContext } from "react-beautiful-dnd"; import { TextChannel, VoiceChannel } from "revolt-api/types/Channels"; import { Category } from "revolt-api/types/Servers"; import { Server } from "revolt.js/dist/maps/Servers"; @@ -12,16 +11,13 @@ import { Text } from "preact-i18n"; import { useCallback, useEffect, useMemo, useState } from "preact/hooks"; import { useAutosave } from "../../../lib/debounce"; +import { Draggable, Droppable } from "../../../lib/dnd"; import { noop } from "../../../lib/js"; import { useIntermediate } from "../../../context/intermediate/Intermediate"; import ChannelIcon from "../../../components/common/ChannelIcon"; -import Button from "../../../components/ui/Button"; -import ComboBox from "../../../components/ui/ComboBox"; -import InputBox from "../../../components/ui/InputBox"; import SaveStatus, { EditStatus } from "../../../components/ui/SaveStatus"; -import Tip from "../../../components/ui/Tip"; const KanbanEntry = styled.div` padding: 2px 4px; @@ -234,86 +230,83 @@ export const Categories = observer(({ server }: Props) => { droppableId="categories" direction="horizontal" type="column"> - {(provided) => - ( -
- + {(provided) => ( +
+ + + {categories.map((category, index) => ( { + setCategories( + categories.map((x) => + x.id === category.id + ? { + ...x, + title, + } + : x, + ), + ); + }} + deleteSelf={() => + setCategories( + categories.filter( + (x) => + x.id !== + category.id, + ), + ) + } + addChannel={(channel) => { + setCategories( + categories.map((x) => + x.id === category.id + ? { + ...x, + channels: [ + ...x.channels, + channel._id, + ], + } + : x, + ), + ); + }} /> - {categories.map((category, index) => ( - { - setCategories( - categories.map((x) => - x.id === category.id - ? { - ...x, - title, - } - : x, - ), - ); - }} - deleteSelf={() => - setCategories( - categories.filter( - (x) => - x.id !== - category.id, - ), - ) - } - addChannel={(channel) => { - setCategories( - categories.map((x) => - x.id === category.id - ? { - ...x, - channels: - [ - ...x.channels, - channel._id, - ], - } - : x, - ), - ); - }} - /> - ))} - -
- - setCategories([ - ...categories, - { - id: ulid(), - title: "New Category", - channels: [], - }, - ]) - }> - - -
-
- {provided.placeholder} -
-
- ) as any - } + ))} + +
+ + setCategories([ + ...categories, + { + id: ulid(), + title: "New Category", + channels: [], + }, + ]) + }> + + +
+
+ {provided.placeholder} +
+
+ )} @@ -366,116 +359,102 @@ function ListElement({ key={category.id} draggableId={category.id} index={index}> - {(provided) => - ( -
- -
- - - {editing ? ( - - setEditing( - e.currentTarget.value, - ) - } - onKeyDown={(e) => - e.key === "Enter" && save() - } - id={category.id} - /> - ) : ( - - {category.title} - - )} - - {deleteSelf && ( - - - + {(provided) => ( +
+ +
+ + + {editing ? ( + + setEditing( + e.currentTarget.value, + ) + } + onKeyDown={(e) => + e.key === "Enter" && save() + } + id={category.id} + /> + ) : ( + + {category.title} + )} - - - {(provided) => - ( -
- {category.channels.map( - (x, index) => { - const channel = - server.client.channels.get( - x, - ); - if (!channel) - return null; - - return ( - - {(provided) => - ( -
- -
- - - { - channel.name - } - -
-
-
- ) as any - } -
- ); - }, - )} - {provided.placeholder} -
- ) as any - } -
- - openScreen({ - id: "special_prompt", - type: "create_channel", - target: server, - cb: addChannel, - }) - }> - -
-
-
- ) as any - } + {deleteSelf && ( + + + + )} +
+ + {(provided) => ( +
+ {category.channels.map((x, index) => { + const channel = + server.client.channels.get(x); + if (!channel) return null; + + return ( + + {(provided) => ( +
+ +
+ + + { + channel.name + } + +
+
+
+ )} +
+ ); + })} + {provided.placeholder} +
+ )} +
+ + openScreen({ + id: "special_prompt", + type: "create_channel", + target: server, + cb: addChannel, + }) + }> + + +
+
+
+ )} ); }