Skip to content

Commit 472a0fc

Browse files
committed
Add file-related functions and update workspace header and editor components
1 parent 444a6be commit 472a0fc

File tree

5 files changed

+247
-39
lines changed

5 files changed

+247
-39
lines changed

app/(routes)/workspace/[fileId]/page.tsx

+52-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
"use client";
2-
import React, { useState } from "react";
2+
import React, { useEffect, useState } from "react";
33
import {
44
ResizableHandle,
55
ResizablePanel,
66
ResizablePanelGroup,
77
} from "@/components/ui/resizable";
88
import WorkSpaceHeader from "../_components/WorkSpaceHeader";
99
import dynamic from "next/dynamic";
10+
import { useConvex } from "convex/react";
11+
import { api } from "@/convex/_generated/api";
12+
import { FILE } from "../../dashboard/_components/DashboardTable";
1013

1114
export const Editor = dynamic(() => import("../_components/Editor"), {
1215
ssr: false,
@@ -16,7 +19,22 @@ export const Canvas = dynamic(() => import("../_components/Canvas"), {
1619
ssr: false,
1720
});
1821

19-
const Workspace = () => {
22+
const Workspace = ({ params }: any) => {
23+
const convex = useConvex();
24+
25+
const [fileData, setfileData] = useState<FILE>();
26+
27+
useEffect(() => {
28+
params.fileId && getFileData();
29+
}, []);
30+
31+
const getFileData = async () => {
32+
const file = await convex.query(api.files.getFilebyId, {
33+
_id: params.fileId,
34+
});
35+
36+
setfileData(file);
37+
};
2038
const Tabs = [
2139
{
2240
name: "Document",
@@ -30,21 +48,30 @@ const Workspace = () => {
3048
];
3149

3250
const [activeTab, setActiveTab] = useState(Tabs[1].name);
33-
51+
const [triggerSave, setTriggerSave] = useState(false);
52+
const [whiteBoard, setWhiteBoard] = useState<any>(
53+
fileData && fileData.whiteboard ? JSON.parse(fileData.whiteboard) : null
54+
);
3455
return (
3556
<div className="overflow-hidden w-full">
3657
<WorkSpaceHeader
3758
Tabs={Tabs}
3859
setActiveTab={setActiveTab}
3960
activeTab={activeTab}
61+
onSave={() => setTriggerSave(!triggerSave)}
62+
file={fileData}
4063
/>
4164
{activeTab === "Document" ? (
4265
<div
4366
style={{
4467
height: "calc(100vh - 3rem)",
4568
}}
4669
>
47-
<Editor />
70+
<Editor
71+
onSaveTrigger={triggerSave}
72+
fileId={params.fileId}
73+
fileData={fileData!}
74+
/>
4875
</div>
4976
) : activeTab === "Both" ? (
5077
<ResizablePanelGroup
@@ -53,12 +80,22 @@ const Workspace = () => {
5380
}}
5481
direction="horizontal"
5582
>
56-
<ResizablePanel defaultSize={100} minSize={40} collapsible={false}>
57-
<Editor />
83+
<ResizablePanel defaultSize={50} minSize={40} collapsible={false}>
84+
<Editor
85+
onSaveTrigger={triggerSave}
86+
fileId={params.fileId}
87+
fileData={fileData!}
88+
/>
5889
</ResizablePanel>
5990
<ResizableHandle className=" bg-neutral-600" />
60-
<ResizablePanel defaultSize={100} minSize={45}>
61-
<Canvas />
91+
<ResizablePanel defaultSize={50} minSize={45}>
92+
<Canvas
93+
onSaveTrigger={triggerSave}
94+
fileId={params.fileId}
95+
fileData={fileData!}
96+
whiteBoard={whiteBoard}
97+
setWhiteBoard={setWhiteBoard}
98+
/>
6299
</ResizablePanel>
63100
</ResizablePanelGroup>
64101
) : activeTab === "Canvas" ? (
@@ -67,7 +104,13 @@ const Workspace = () => {
67104
height: "calc(100vh - 3rem)",
68105
}}
69106
>
70-
<Canvas />
107+
<Canvas
108+
onSaveTrigger={triggerSave}
109+
fileId={params.fileId}
110+
fileData={fileData!}
111+
whiteBoard={whiteBoard}
112+
setWhiteBoard={setWhiteBoard}
113+
/>
71114
</div>
72115
) : null}
73116
</div>

app/(routes)/workspace/_components/Canvas.tsx

+92-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,100 @@
11
"use client";
2-
import React from "react";
3-
import { Excalidraw } from "@excalidraw/excalidraw";
2+
import React, { useEffect, useRef, useState } from "react";
3+
import { Excalidraw, MainMenu, WelcomeScreen } from "@excalidraw/excalidraw";
4+
import { FILE } from "../../dashboard/_components/DashboardTable";
5+
import { useMutation } from "convex/react";
6+
import { api } from "@/convex/_generated/api";
7+
import { toast } from "sonner";
8+
9+
const Canvas = ({
10+
onSaveTrigger,
11+
fileId,
12+
fileData,
13+
whiteBoard,
14+
setWhiteBoard,
15+
}: {
16+
onSaveTrigger: any;
17+
fileId: any;
18+
fileData: FILE;
19+
whiteBoard: any;
20+
setWhiteBoard: any;
21+
}) => {
22+
useEffect(() => {
23+
saveWhiteboard();
24+
}, [onSaveTrigger]);
25+
26+
const updateWhiteBoard = useMutation(api.files.updateWhiteboard);
27+
28+
const saveWhiteboard = () => {
29+
updateWhiteBoard({
30+
_id: fileId,
31+
whiteboard: JSON.stringify(whiteBoard),
32+
})
33+
.then(() => {
34+
toast.success("Canvas saved");
35+
})
36+
.catch((e) => {
37+
toast.error("Error saving canvas");
38+
});
39+
};
440

5-
const Canvas = () => {
641
return (
742
<>
843
<div className="h-full w-full">
9-
<Excalidraw theme="dark" />
44+
{fileData && fileData.whiteboard ? (
45+
<Excalidraw
46+
theme="dark"
47+
initialData={{
48+
elements: fileData && JSON.parse(fileData?.whiteboard),
49+
}}
50+
UIOptions={{
51+
canvasActions: {
52+
export: false,
53+
loadScene: false,
54+
saveAsImage: false,
55+
},
56+
}}
57+
onChange={(excaliDrawElements, appState, files) => {
58+
setWhiteBoard(excaliDrawElements);
59+
}}
60+
>
61+
<MainMenu>
62+
<MainMenu.DefaultItems.ClearCanvas />
63+
<MainMenu.DefaultItems.Help />
64+
<MainMenu.DefaultItems.ChangeCanvasBackground />
65+
</MainMenu>
66+
<WelcomeScreen>
67+
<WelcomeScreen.Hints.MenuHint />
68+
<WelcomeScreen.Hints.ToolbarHint />
69+
<WelcomeScreen.Hints.HelpHint />
70+
</WelcomeScreen>
71+
</Excalidraw>
72+
) : (
73+
<Excalidraw
74+
theme="dark"
75+
UIOptions={{
76+
canvasActions: {
77+
export: false,
78+
loadScene: false,
79+
saveAsImage: false,
80+
},
81+
}}
82+
onChange={(excaliDrawElements, appState, files) => {
83+
setWhiteBoard(excaliDrawElements);
84+
}}
85+
>
86+
<MainMenu>
87+
<MainMenu.DefaultItems.ClearCanvas />
88+
<MainMenu.DefaultItems.Help />
89+
<MainMenu.DefaultItems.ChangeCanvasBackground />
90+
</MainMenu>
91+
<WelcomeScreen>
92+
<WelcomeScreen.Hints.MenuHint />
93+
<WelcomeScreen.Hints.ToolbarHint />
94+
<WelcomeScreen.Hints.HelpHint />
95+
</WelcomeScreen>
96+
</Excalidraw>
97+
)}
1098
</div>
1199
</>
12100
);

app/(routes)/workspace/_components/Editor.tsx

+57-14
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,95 @@
11
"use client";
2-
import React, { useEffect, useRef } from "react";
2+
import React, { useEffect, useRef, useState } from "react";
33
import EditorJs from "@editorjs/editorjs";
44
import Header from "@editorjs/header";
55
// @ts-ignore
66
import List from "@editorjs/list";
77
// @ts-ignore
88
import checkList from "@editorjs/checklist";
9+
import { Edu_QLD_Beginner } from "next/font/google";
10+
import { useMutation } from "convex/react";
11+
import { api } from "@/convex/_generated/api";
12+
import { toast } from "sonner";
13+
import { FILE } from "../../dashboard/_components/DashboardTable";
914

10-
const rawDocument = {};
15+
const rawDocument = {
16+
time: 1550476186479,
17+
blocks: [
18+
{
19+
id: "oUq2g_tl8y",
20+
type: "header",
21+
data: {
22+
text: "Untitled Document",
23+
level: 2,
24+
},
25+
},
26+
],
27+
version: "2.8.1",
28+
};
1129

12-
const Editor = () => {
30+
const Editor = ({
31+
onSaveTrigger,
32+
fileId,
33+
fileData,
34+
}: {
35+
onSaveTrigger: any;
36+
fileId: any;
37+
fileData: FILE;
38+
}) => {
1339
const ref = useRef<EditorJs>();
40+
const [document, setDocument] = useState(rawDocument);
41+
42+
const updateDocument = useMutation(api.files.updateDocument);
43+
44+
useEffect(() => {
45+
fileData && initEditor();
46+
}, [fileData]);
47+
1448
useEffect(() => {
15-
initEditor();
16-
}, []);
49+
console.log("triggered" + onSaveTrigger);
50+
onDocumentSave();
51+
}, [onSaveTrigger]);
1752

1853
const initEditor = () => {
1954
const editor = new EditorJs({
2055
holder: "editorjs",
2156
placeholder: "Let`s write an awesome story!",
22-
2357
tools: {
2458
header: {
2559
// @ts-ignore
2660
class: Header,
2761
inlineToolbar: true,
2862
shortcut: "CMD+SHIFT+H",
63+
placeholder: "Enter a heading",
2964
},
3065
list: List,
3166
checklist: checkList,
3267
},
68+
data: fileData.document ? JSON.parse(fileData.document) : document,
69+
});
70+
editor.isReady.then(() => {
71+
ref.current = editor;
3372
});
34-
editor.isReady
35-
.then(() => {
36-
console.log("Editor.js is ready to work!");
37-
})
38-
.catch((reason) => {
39-
console.log(`Editor.js initialization failed because of ${reason}`);
73+
};
74+
75+
const onDocumentSave = async () => {
76+
if (ref.current) {
77+
const savedData = await ref.current.save();
78+
const resp = await updateDocument({
79+
_id: fileId,
80+
document: JSON.stringify(savedData),
4081
});
41-
ref.current = editor;
82+
83+
toast.success("Document Saved");
84+
}
4285
};
4386

4487
return (
4588
<div className="p-2">
46-
<h1 className="text-white text-lg font-medium">Editor</h1>
4789
<div
4890
className="text-white selection:text-black selection:bg-neutral-400 overflow-x-hidden overflow-y-auto w-full pr-4 pl-2 h-[85vh] mb-4"
4991
id="editorjs"
92+
key={"editorjs"}
5093
></div>
5194
</div>
5295
);

app/(routes)/workspace/_components/WorkSpaceHeader.tsx

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
"use client";
2+
import { Button } from "@/components/ui/button";
23
import { cn } from "@/lib/utils";
3-
import {
4-
GitBranch,
5-
GitBranchPlus,
6-
Github,
7-
Info,
8-
Link,
9-
MoreHorizontal,
10-
Save,
11-
} from "lucide-react";
4+
5+
import { Github, Info, Link, MoreHorizontal, Save } from "lucide-react";
126
import React from "react";
137

14-
const WorkSpaceHeader = ({ Tabs, setActiveTab, activeTab }: any) => {
8+
const WorkSpaceHeader = ({
9+
Tabs,
10+
setActiveTab,
11+
activeTab,
12+
onSave,
13+
file,
14+
}: any) => {
1515
return (
1616
<div className="border-b border-neutral-800 h-12 flex items-center px-4 w-full">
1717
{/* file name portion */}
1818
<div className="flex space-x-2 items-center justify-start w-full">
1919
<img src="/logo.svg" alt="logo" className="w-8 h-8" />
2020
<div>
21-
<h1 className="text-sm font-medium">File Name</h1>
21+
<h1 className="text-sm font-medium">
22+
{file ? file.fileName : "Untitled"}
23+
</h1>
2224
</div>
2325
<div className="rounded-sm hover:bg-neutral-700 hover:text-white cursor-pointer p-1">
2426
<MoreHorizontal size={16} />
@@ -60,7 +62,10 @@ const WorkSpaceHeader = ({ Tabs, setActiveTab, activeTab }: any) => {
6062
Give Star on GitHub
6163
<Github size={16} className="ml-2" />
6264
</div>
63-
<div className="rounded-sm flex text-sm items-center bg-blue-700 hover:bg-blue-800 hover:text-white cursor-pointer px-2 py-1">
65+
<div
66+
onClick={() => onSave()}
67+
className="rounded-sm flex text-sm items-center bg-blue-700 hover:bg-blue-800 hover:text-white cursor-pointer px-2 py-1"
68+
>
6469
<Save size={20} />
6570
</div>
6671
<div className="rounded-sm flex text-sm items-center bg-blue-700 hover:bg-blue-800 hover:text-white cursor-pointer px-2 py-1">

0 commit comments

Comments
 (0)