Skip to content

Commit

Permalink
```feat(board): 添加图层移动和排列工具
Browse files Browse the repository at this point in the history
在选择工具组件中引入新功能,允许用户在画布上移动和排列所选图层。这包括:
- 将图层移到最前面
- 向前移动一层
- 向后移动一层
- 将图层移到最后面

这些操作通过使用Lucide图标作为按钮来实现,每个按钮都有相关的工具提示指示其功能。这些工具集成在画布界面的右侧工具栏中。
```
  • Loading branch information
YuniqueUnic committed Aug 25, 2024
1 parent 3e749a1 commit a3c1bcc
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 3 deletions.
2 changes: 1 addition & 1 deletion app/board/[boardId]/_components/color-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const ColorPicker = ({
onChange
}: ColorPickerProps) => {
return <div className="flex flex-wrap gap-2 items-center max-w-[164px]
p-2 mr-2 border-r border-neutral-200">
mr-2 border-r border-neutral-200">
{Colors.map((color, index) => {
return (
<ColorButton
Expand Down
161 changes: 159 additions & 2 deletions app/board/[boardId]/_components/selection-tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,26 @@

import { memo } from "react";

import {
ArrowUpIcon,
ArrowDownIcon,
BringToFront,
SendToBack,
Trash2
} from "lucide-react";


import { ColorPicker } from "./color-picker";

import { Camera, Color } from "@/types/canvas";

import { useMutation, useSelf } from "@liveblocks/react";

import { useDeleteLayers } from "@/hooks/use-delete-layers";
import { useSelectionBounds } from "@/hooks/use-selection-bounds";

import { Hint } from "@/components/hint";
import { Button } from "@/components/ui/button";
import { Trash2 } from "lucide-react";



Expand All @@ -25,6 +35,92 @@ export const SelectionTools = memo((
) => {
const selection = useSelf((me) => me.presence.selection);

const moveToFront = useMutation((
{ storage }
) => {
const liveLayerIds = storage.get("layerIds");

const indices: number[] = []; // the indices of selection layer ids in the liveLayerIds array

const arr = liveLayerIds.toArray();

for (let i = 0; i < arr.length; i++) {
if (selection?.includes(arr[i])) {
indices.push(i);
}
}

for (let i = indices.length - 1; i >= 0; i--) {
liveLayerIds.move(
indices[i],
arr.length - 1 - (indices.length - 1 - i)
);
}

}, [selection]);

const moveLayerAction = useMutation((
{ storage },
direction: "up" | "down",
index: number
) => {
const liveLayerIds = storage.get("layerIds");
const arr = liveLayerIds.toArray();
const indices: number[] = arr
.map((layerId, idx) => selection?.includes(layerId) ? idx : -1)
.filter(idx => idx !== -1);

// console.log("indices", indices);
// console.log("arr", arr);

// Ensure the index is within the bounds of the array
index = Math.min(index, arr.length - 1);
index = Math.max(index, 0);

if (direction === "up") {
// Move up
const minIndex = Math.min(...indices);
const newIndex = minIndex + 1 < arr.length ? minIndex + 1 : arr.length - 1;

// Move the selected layers to the new positions
for (let i = 0; i < indices.length; i++) {
liveLayerIds.move(indices[i], newIndex + i);
}
} else if (direction === "down") {
// Move down
const maxIndex = Math.max(...indices);
const newIndex = maxIndex - 1 >= 0 ? maxIndex - 1 : 0;

// Move the selected layers to the new positions
for (let i = indices.length - 1; i >= 0; i--) {
liveLayerIds.move(indices[i], newIndex - (indices.length - 1 - i));
}
}

}, [selection]);

const moveToBack = useMutation((
{ storage }
) => {
const liveLayerIds = storage.get("layerIds");

const indices: number[] = []; // the indices of selection layer ids in the liveLayerIds array

const arr = liveLayerIds.toArray();

for (let i = 0; i < arr.length; i++) {
if (selection?.includes(arr[i])) {
indices.push(i);
}
}

for (let i = 0; i < indices.length; i++) {
liveLayerIds.move(indices[i], i);
}
}, [selection]);



const setFill = useMutation((
{ storage },
fill: Color
Expand Down Expand Up @@ -62,7 +158,68 @@ export const SelectionTools = memo((
<ColorPicker
onChange={setFill}
/>
<div className="flex items-center border-l pl-2 ml-2">
<div className="flex flex-col gap-y-1.5 justify-center items-center">
{/* Bring to front */}
<Hint
label="Bring to front"
side="right"
sideOffset={18}>
<Button
className="w-full"
onClick={moveToFront}
variant={"board"}
size={"icon"}>
<BringToFront className="w-8 h-8" />
</Button>
</Hint>

{/* Move 1 layer up/down */}
<div
className="flex flex-row items-center gap-x-1.5">
{/* Move up */}
<Hint
label="Move up 1 layer"
side="right"
sideOffset={48}>
<Button
asChild
onClick={() => { return moveLayerAction("up", 1); }}
variant={"board"}
size={"icon"}>
<ArrowUpIcon className="w-6 h-6" />
</Button>
</Hint>

{/* Move down */}
<Hint
label="Move down 1 layer"
side="right"
sideOffset={48}>
<Button
asChild
onClick={() => { return moveLayerAction("down", 1); }}
variant={"board"}
size={"icon"}>
<ArrowDownIcon className="w-6 h-6" />
</Button>
</Hint>
</div>

{/* Send to back */}
<Hint
label="Send to back"
side="right"
sideOffset={18}>
<Button
className="w-full"
onClick={moveToBack}
variant={"board"}
size={"icon"}>
<SendToBack className="w-8 h-8" />
</Button>
</Hint>
</div>
<div className="flex items-center border-l pl-1 ml-2">
<Hint
label="Delete"
side={"right"}
Expand Down

0 comments on commit a3c1bcc

Please sign in to comment.