Merge branch 'main' into dark-mode-implementation

This commit is contained in:
Desmond Grealy
2023-01-02 00:49:03 -08:00
158 changed files with 10576 additions and 3799 deletions
+70 -33
View File
@@ -1,4 +1,23 @@
import { Flex } from "@chakra-ui/react";
import {
closestCenter,
DndContext,
PointerSensor,
TouchSensor,
KeyboardSensor,
useSensor,
useSensors,
} from "@dnd-kit/core";
import type { DragEndEvent } from "@dnd-kit/core/dist/types/events";
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { ReactNode, useEffect, useState } from "react";
import { SortableItem } from "./SortableItem";
export interface SortableProps {
@@ -6,43 +25,61 @@ export interface SortableProps {
onChange: (newSortedIndices: number[]) => void;
}
export const Sortable = ({ items, onChange }) => {
const [sortOrder, setSortOrder] = useState<number[]>([]);
interface SortableItems {
id: number;
originalIndex: number;
item: ReactNode;
}
const update = (newRanking: number[]) => {
setSortOrder(newRanking);
onChange(newRanking);
};
export const Sortable = ({ items, onChange }: SortableProps) => {
const [itemsWithIds, setItemsWithIds] = useState<SortableItems[]>([]);
useEffect(() => {
const indices = Array.from({ length: items.length }).map((_, i) => i);
setSortOrder(indices);
onChange(indices);
}, [items, onChange]);
setItemsWithIds(
items.map((item, idx) => ({
item,
id: idx + 1, // +1 because dndtoolkit has problem with "falsy" ids
originalIndex: idx,
}))
);
}, [items]);
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(TouchSensor),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
return (
<ul className="flex flex-col gap-4">
{sortOrder.map((rank, i) => (
<SortableItem
key={`${rank}`}
canIncrement={i > 0}
onIncrement={() => {
const newRanking = sortOrder.slice();
const newIdx = i - 1;
[newRanking[i], newRanking[newIdx]] = [newRanking[newIdx], newRanking[i]];
update(newRanking);
}}
canDecrement={i < sortOrder.length - 1}
onDecrement={() => {
const newRanking = sortOrder.slice();
const newIdx = i + 1;
[newRanking[i], newRanking[newIdx]] = [newRanking[newIdx], newRanking[i]];
update(newRanking);
}}
>
{items[rank]}
</SortableItem>
))}
</ul>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
modifiers={[restrictToVerticalAxis]}
>
<SortableContext items={itemsWithIds} strategy={verticalListSortingStrategy}>
<Flex direction="column" gap={2}>
{itemsWithIds.map(({ id, item }) => (
<SortableItem key={id} id={id}>
{item}
</SortableItem>
))}
</Flex>
</SortableContext>
</DndContext>
);
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (active.id === over.id) {
return;
}
setItemsWithIds((items) => {
const oldIndex = items.findIndex((x) => x.id === active.id);
const newIndex = items.findIndex((x) => x.id === over.id);
const newArray = arrayMove(items, oldIndex, newIndex);
onChange(newArray.map((item) => item.originalIndex));
return newArray;
});
}
};
@@ -1,40 +1,32 @@
<<<<<<< HEAD
import { ArrowDownIcon, ArrowUpIcon } from "@heroicons/react/20/solid";
=======
>>>>>>> main
import { Button } from "@chakra-ui/react";
import clsx from "clsx";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { RxDragHandleDots2 } from "react-icons/rx";
import { PropsWithChildren } from "react";
export interface SortableItemProps {
canIncrement: boolean;
canDecrement: boolean;
onIncrement: () => void;
onDecrement: () => void;
children: React.ReactNode;
}
export const SortableItem = ({ children, id }: PropsWithChildren<{ id: number }>) => {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
touchAction: "none",
};
export const SortableItem = ({ canIncrement, canDecrement, onIncrement, onDecrement, children }: SortableItemProps) => {
return (
<li className="grid grid-cols-[min-content_1fr] items-center rounded-lg shadow-md gap-x-2 p-2">
<ArrowButton active={canIncrement} onClick={onIncrement}>
<ArrowUpIcon width={28} />
</ArrowButton>
<span style={{ gridRow: "span 2" }}>{children}</span>
<ArrowButton active={canDecrement} onClick={onDecrement}>
<ArrowDownIcon width={28} />
</ArrowButton>
<li
className="grid grid-cols-[min-content_1fr] items-center rounded-lg shadow-md gap-x-2 p-2 bg-white hover:bg-slate-50"
ref={setNodeRef}
style={style}
>
<Button justifyContent="center" variant="ghost" {...attributes} {...listeners}>
<RxDragHandleDots2 />
</Button>
{children}
</li>
);
};
interface ArrowButtonProps {
active: boolean;
onClick: () => void;
children: React.ReactNode;
}
const ArrowButton = ({ children, active, onClick }: ArrowButtonProps) => {
return (
<Button justifyContent="center" variant="ghost" onClick={onClick} disabled={!active}>
{children}
</Button>
);
};