feat : update UI
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { toast } from "sonner";
|
||||
@@ -742,6 +743,52 @@ function VisualRecommendationGrid({
|
||||
);
|
||||
}
|
||||
|
||||
function SortableTeam({
|
||||
id,
|
||||
position,
|
||||
children,
|
||||
}: {
|
||||
id: string;
|
||||
position: number;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({ id });
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
style={{ transform: CSS.Transform.toString(transform), transition }}
|
||||
className={cn(isDragging && "relative z-10 opacity-60")}
|
||||
>
|
||||
<Card size="sm">
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-sm font-medium">Team {position + 1}</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
className="touch-none"
|
||||
aria-label={`Drag to reorder team ${position + 1}`}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
>
|
||||
<GripVerticalIcon />
|
||||
</Button>
|
||||
</div>
|
||||
{children}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BossRecommendationEditor({
|
||||
scheduleId,
|
||||
version,
|
||||
@@ -776,6 +823,13 @@ function BossRecommendationEditor({
|
||||
.filter((group) => group.kind === "unit")
|
||||
.flatMap((group) => group.items.flatMap((item) => toInput(item) ?? [])),
|
||||
);
|
||||
const teamSensors = useSensors(
|
||||
useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
}),
|
||||
);
|
||||
const teamIds = teams.map((_, index) => `team-${index}`);
|
||||
const fingerprint = JSON.stringify({ teams, units });
|
||||
const valid = teams.every(
|
||||
(team) =>
|
||||
@@ -868,9 +922,28 @@ function BossRecommendationEditor({
|
||||
<div className="flex min-w-0 flex-col gap-6">
|
||||
<FieldSet className="gap-3">
|
||||
<FieldLegend>Recommended team</FieldLegend>
|
||||
{teams.map((team, teamIndex) => (
|
||||
<Card key={teamIndex} size="sm">
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
<DndContext
|
||||
sensors={teamSensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={({ active, over }) => {
|
||||
if (!over || active.id === over.id) return;
|
||||
const from = teamIds.indexOf(String(active.id));
|
||||
const to = teamIds.indexOf(String(over.id));
|
||||
if (from >= 0 && to >= 0)
|
||||
setTeams((current) => arrayMove(current, from, to));
|
||||
}}
|
||||
>
|
||||
<SortableContext
|
||||
items={teamIds}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
{teams.map((team, teamIndex) => (
|
||||
<SortableTeam
|
||||
key={teamIds[teamIndex]}
|
||||
id={teamIds[teamIndex]}
|
||||
position={teamIndex}
|
||||
>
|
||||
<VisualRecommendationGrid
|
||||
items={team}
|
||||
limit={4}
|
||||
@@ -908,9 +981,11 @@ function BossRecommendationEditor({
|
||||
<Trash2Icon data-icon="inline-start" />
|
||||
Remove team
|
||||
</DeleteConfirmationDialog>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</SortableTeam>
|
||||
))}
|
||||
</div>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user