Skip to content

Commit 2a29119

Browse files
committed
chore!: enable dynamic import and client-side rendering for entire app
1 parent 3872f07 commit 2a29119

File tree

13 files changed

+259
-254
lines changed

13 files changed

+259
-254
lines changed

app/(root)/page.tsx

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
"use client";
2+
3+
import LeftSidebar from "@/components/layout/left-sidebar";
4+
import Navbar from "@/components/layout/navbar";
5+
import RightSidebar from "@/components/layout/right-sidebar";
6+
import Live from "@/components/live";
7+
import { useEffect, useRef, useState } from "react";
8+
import { fabric } from "fabric";
9+
import {
10+
handleCanvasMouseDown,
11+
handleCanvasMouseUp,
12+
handleCanvasObjectModified,
13+
handleCanvasObjectScaling,
14+
handleCanvasSelectionCreated,
15+
handleCanvaseMouseMove,
16+
handlePathCreated,
17+
handleResize,
18+
initializeFabric,
19+
renderCanvas,
20+
} from "@/lib/canvas";
21+
import type { ActiveElement, Attributes } from "@/types";
22+
import { useMutation, useRedo, useStorage, useUndo } from "@/liveblocks.config";
23+
import { defaultNavElement } from "@/constants";
24+
import { handleDelete, handleKeyDown } from "@/lib/key-events";
25+
import { handleImageUpload } from "@/lib/shapes";
26+
27+
export default function Home() {
28+
const undo = useUndo();
29+
const redo = useRedo();
30+
31+
const canvasRef = useRef<HTMLCanvasElement>(null);
32+
const fabricRef = useRef<fabric.Canvas | null>(null);
33+
const isDrawing = useRef<boolean>(false);
34+
const shapeRef = useRef<fabric.Object | null>(null);
35+
const selectedShapeRef = useRef<string | null>(null);
36+
const activeObjectRef = useRef<fabric.Object | null>(null);
37+
const imageInputRef = useRef<HTMLInputElement | null>(null);
38+
const isEditingRef = useRef<boolean>(false);
39+
40+
const canvasObjects = useStorage(root => root.canvasObjects);
41+
42+
const [elementAttributes, setElementAttributes] = useState<Attributes>({
43+
width: "",
44+
height: "",
45+
fontSize: "",
46+
fontFamily: "",
47+
fontWeight: "",
48+
fill: "#aabbcc",
49+
stroke: "#aabbcc",
50+
});
51+
52+
const syncShapeInStorage = useMutation(({ storage }, object) => {
53+
if (!object) return;
54+
55+
const { objectId } = object;
56+
57+
const shapeData = object.toJSON();
58+
shapeData.objectId = objectId;
59+
60+
const canvasObjects = storage.get("canvasObjects");
61+
62+
canvasObjects.set(objectId, shapeData);
63+
}, []);
64+
65+
const [activeElement, setActiveElement] = useState<ActiveElement>({
66+
name: "",
67+
value: "",
68+
icon: "",
69+
});
70+
71+
const deleteAllShapes = useMutation(({ storage }) => {
72+
const canvasObjects = storage.get("canvasObjects");
73+
74+
if (!canvasObjects || canvasObjects.size === 0) return true;
75+
76+
const entries = Array.from(canvasObjects.entries());
77+
78+
for (const [key] of entries) {
79+
canvasObjects.delete(key);
80+
}
81+
82+
return canvasObjects.size === 0;
83+
}, []);
84+
85+
const deleteShapeFromStorage = useMutation(({ storage }, objectId) => {
86+
const canvasObjects = storage.get("canvasObjects");
87+
88+
if (!canvasObjects || canvasObjects.size === 0) return;
89+
90+
canvasObjects.delete(objectId);
91+
}, []);
92+
93+
const handleActiveElement = (elem: ActiveElement) => {
94+
setActiveElement(elem);
95+
96+
switch (elem?.value) {
97+
case "reset":
98+
deleteAllShapes();
99+
fabricRef.current?.clear();
100+
setActiveElement(defaultNavElement);
101+
break;
102+
case "delete":
103+
handleDelete(fabricRef.current as any, deleteShapeFromStorage);
104+
setActiveElement(defaultNavElement);
105+
break;
106+
case "image":
107+
imageInputRef.current?.click();
108+
isDrawing.current = false;
109+
110+
if (fabricRef.current) {
111+
fabricRef.current.isDrawingMode = false;
112+
}
113+
break;
114+
default:
115+
break;
116+
}
117+
selectedShapeRef.current = elem?.value as string;
118+
};
119+
120+
useEffect(() => {
121+
const canvas = initializeFabric({ canvasRef, fabricRef });
122+
123+
canvas.on("mouse:down", (options: any) => {
124+
handleCanvasMouseDown({
125+
options,
126+
canvas,
127+
isDrawing,
128+
shapeRef,
129+
selectedShapeRef,
130+
});
131+
});
132+
133+
canvas.on("mouse:move", (options: any) => {
134+
handleCanvaseMouseMove({
135+
options,
136+
canvas,
137+
isDrawing,
138+
shapeRef,
139+
selectedShapeRef,
140+
syncShapeInStorage,
141+
});
142+
});
143+
144+
canvas.on("mouse:up", () => {
145+
handleCanvasMouseUp({
146+
canvas,
147+
isDrawing,
148+
shapeRef,
149+
selectedShapeRef,
150+
syncShapeInStorage,
151+
setActiveElement,
152+
activeObjectRef,
153+
});
154+
});
155+
156+
canvas.on("path:created", (options: any) => {
157+
handlePathCreated({
158+
options,
159+
syncShapeInStorage,
160+
});
161+
});
162+
163+
canvas.on("object:modified", (options: any) => {
164+
handleCanvasObjectModified({
165+
options,
166+
syncShapeInStorage,
167+
});
168+
});
169+
170+
canvas.on("object:scaling", (options: any) => {
171+
handleCanvasObjectScaling({
172+
options,
173+
setElementAttributes,
174+
});
175+
});
176+
177+
canvas.on("selection:created", (options: any) => {
178+
handleCanvasSelectionCreated({
179+
options,
180+
isEditingRef,
181+
setElementAttributes,
182+
});
183+
});
184+
185+
window.addEventListener("resize", () => {
186+
handleResize({ canvas: fabricRef.current as fabric.Canvas | any });
187+
});
188+
189+
window.addEventListener("keydown", (e: any) => {
190+
handleKeyDown({
191+
e,
192+
canvas: fabricRef.current as fabric.Canvas | any,
193+
undo,
194+
redo,
195+
syncShapeInStorage,
196+
deleteShapeFromStorage,
197+
});
198+
});
199+
200+
return () => {
201+
canvas.dispose();
202+
};
203+
// eslint-disable-next-line react-hooks/exhaustive-deps
204+
}, []);
205+
206+
useEffect(() => {
207+
renderCanvas({
208+
fabricRef,
209+
canvasObjects,
210+
activeObjectRef,
211+
});
212+
}, [canvasObjects]);
213+
214+
return (
215+
<main className="h-screen overflow-hidden">
216+
<Navbar
217+
activeElement={activeElement}
218+
handleActiveElement={handleActiveElement}
219+
imageInputRef={imageInputRef}
220+
handleImageUpload={(e: any) => {
221+
e.stopPropagation();
222+
223+
handleImageUpload({
224+
file: e.target.files[0],
225+
canvas: fabricRef as fabric.Canvas | any,
226+
shapeRef,
227+
syncShapeInStorage,
228+
});
229+
}}
230+
/>
231+
232+
<section className="flex h-full flex-row">
233+
<LeftSidebar allShapes={Array.from(canvasObjects)} />
234+
<Live canvasRef={canvasRef} undo={undo} redo={redo} />
235+
<RightSidebar
236+
elementAttributes={elementAttributes}
237+
setElementAttributes={setElementAttributes}
238+
fabricRef={fabricRef}
239+
isEditingRef={isEditingRef}
240+
activeObjectRef={activeObjectRef}
241+
syncShapeInStorage={syncShapeInStorage}
242+
/>
243+
</section>
244+
</main>
245+
);
246+
}

0 commit comments

Comments
 (0)