Skip to content

Commit

Permalink
```plaintext
Browse files Browse the repository at this point in the history
feat(canvas): 添加键盘快捷键和橡皮草稿可视化

- 绑定Ctrl+Z和Ctrl+Shift+Z键盘快捷键分别用于撤销和重做操作。
- 在Canvas组件中可视化自己的草稿以及他人的草稿。
- 重构CursorPresence组件,区分用户光标和草稿视觉化。
- 通过useDisableScrollBounce钩子禁用滚动反弹效果。
- 修复SelectionBox组件中的注释,并优化代码风格。
```
  • Loading branch information
YuniqueUnic committed Aug 28, 2024
1 parent e6fa740 commit c722619
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 15 deletions.
63 changes: 56 additions & 7 deletions app/board/[boardId]/_components/canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import React, { useCallback, useMemo, useState } from "react";
import React, { useCallback, useMemo, useState, useEffect } from "react";

import { nanoid } from "nanoid";

Expand All @@ -11,7 +11,8 @@ import {
useCanRedo,
useMutation,
useStorage,
useOthersMapped
useOthersMapped,
useSelf
} from "@liveblocks/react";
import { LiveObject } from "@liveblocks/client";

Expand All @@ -25,8 +26,10 @@ import {
XYWH,
Side
} from "@/types/canvas";
import { useDisableScrollBounce } from "@/hooks/use-disable-scroll-bounce";

import { Info } from "./info";
import { Path } from "./path";
import { Toolbar } from "./toolbar";
import { Participants } from "./participants";
import { LayerPreview } from "./layer-preview";
Expand All @@ -35,8 +38,10 @@ import { SelectionTools } from "./selection-tools";
import { CursorsPresence } from "./cursors-presence";


import { connectionIdToColor, findIntersectingLayersWithRectangle, penPointToPathLayer, pointerEventToCanvasEvent, resizeBounds } from "@/lib/utils";
import { colorToCss, connectionIdToColor, findIntersectingLayersWithRectangle, penPointToPathLayer, pointerEventToCanvasEvent, resizeBounds } from "@/lib/utils";
import { SelectionFontTools } from "./selection-font-tools";
import { useDeleteLayers } from "@/hooks/use-delete-layers";



// import { useQuery } from "convex/react";
Expand All @@ -55,6 +60,8 @@ interface CanvasProps {
export const Canvas = ({ boardId }: CanvasProps) => {
const layerIds = useStorage((root) => root.layerIds);

const pencilDraft = useSelf((me) => me.presence.pencilDraft);

const [camera, setCamera] = useState<Camera>({ x: 0, y: 0 });
const [lastUsedColor, setLastUserColor] = useState<Color>({
r: 0,
Expand All @@ -66,6 +73,9 @@ export const Canvas = ({ boardId }: CanvasProps) => {
mode: CanvasMode.None
});



useDisableScrollBounce();
const history = useHistory();
// const undo = useUndo();
// const redo = useRedo();
Expand Down Expand Up @@ -285,10 +295,12 @@ export const Canvas = ({ boardId }: CanvasProps) => {
corner: Side,
initialBounds: XYWH,) => {

console.log({
corner,
initialBounds
});
// TODO: Add resize handle for Pencil

// console.log({
// corner,
// initialBounds
// });

history.pause();

Expand Down Expand Up @@ -459,6 +471,36 @@ export const Canvas = ({ boardId }: CanvasProps) => {
return layerIdsToColorSelection;
}, [selections]);

const deleteLayers = useDeleteLayers();

useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
switch (e.key) {
case "z":
{
if (e.ctrlKey || e.metaKey) {
if (e.shiftKey) {
history.redo();
} else {
history.undo();
}
}
break;
}
default:
break;
}
}


document.addEventListener("keydown", onKeyDown);

return () => {
document.removeEventListener("keydown", onKeyDown);
};
},
[deleteLayers, history]);


return (
<main className="w-full h-full relative bg-neutral-100 touch-none">
Expand Down Expand Up @@ -508,6 +550,13 @@ export const Canvas = ({ boardId }: CanvasProps) => {
/>
)}
<CursorsPresence />
{pencilDraft != null && pencilDraft.length > 0 && (
<Path
x={0}
y={0}
points={pencilDraft}
fill={colorToCss(lastUsedColor)} />
)}
</g>
</svg>
</main>
Expand Down
35 changes: 33 additions & 2 deletions app/board/[boardId]/_components/cursors-presence.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { memo } from "react";

import { Cursor } from "./cursor";

import { useOthersConnectionIds } from "@liveblocks/react";
import {
shallow,
useOthersMapped,
useOthersConnectionIds,
} from "@liveblocks/react";
import { Path } from "./path";
import { colorToCss } from "@/lib/utils";

const Cursors = () => {
const ids = useOthersConnectionIds();
Expand All @@ -20,11 +26,36 @@ const Cursors = () => {
);
};

const Drafts = () => {
const others = useOthersMapped((other) => ({
pencilDraft: other.presence.pencilDraft,
penColor: other.presence.penColor
}), shallow);

return (
<>
{
others.map(([key, other]) => {
if (other.pencilDraft) {
return <Path
x={0}
y={0}
points={other.pencilDraft}
fill={other.penColor ? colorToCss(other.penColor) : "#000"} />;
}

return null;
})
}
</>
);
};

export const CursorsPresence = memo(() => {
return (
<>

{/* TODO: Draft Pencil */}
<Drafts />
<Cursors />
</>
);
Expand Down
1 change: 0 additions & 1 deletion app/board/[boardId]/_components/selection-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ export const SelectionBox = memo(({
onPointerDown={(e) => {
e.stopPropagation();
onResizeHandlePointerDown(Side.Left, bounds);
// TODO:Add Resize handler
}}
/>
</>
Expand Down
6 changes: 3 additions & 3 deletions app/board/[boardId]/_components/selection-tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const SelectionTools = memo((

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

const arr = liveLayerIds.toArray();
const arr = liveLayerIds.toImmutable();

for (let i = 0; i < arr.length; i++) {
if (selection?.includes(arr[i])) {
Expand All @@ -66,7 +66,7 @@ export const SelectionTools = memo((
index: number
) => {
const liveLayerIds = storage.get("layerIds");
const arr = liveLayerIds.toArray();
const arr = liveLayerIds.toImmutable();
const indices: number[] = arr
.map((layerId, idx) => selection?.includes(layerId) ? idx : -1)
.filter(idx => idx !== -1);
Expand Down Expand Up @@ -107,7 +107,7 @@ export const SelectionTools = memo((

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

const arr = liveLayerIds.toArray();
const arr = liveLayerIds.toImmutable();

for (let i = 0; i < arr.length; i++) {
if (selection?.includes(arr[i])) {
Expand Down
4 changes: 2 additions & 2 deletions app/board/[boardId]/_components/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ export const Toolbar = ({

const actions: Tool[] = [
{
label: "Undo",
label: "Undo (Ctrl + z)",
icon: Undo2,
},
{
label: "Redo",
label: "Redo (Ctr + Shift + z)",
icon: Redo2,
}
];
Expand Down
19 changes: 19 additions & 0 deletions hooks/use-disable-scroll-bounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect } from "react";

export const useDisableScrollBounce = () => {
useEffect(() => {
document.body.classList.add(
"overscroll-none",
"overflow-hidden",
// "disable-scroll-bounce"
);

return () => {
document.body.classList.remove(
"overscroll-none",
"overflow-hidden",
// "disable-scroll-bounce"
);
};
}, []);
};

0 comments on commit c722619

Please sign in to comment.