Skip to content

Commit 9438a94

Browse files
authored
feat: enhance drawing functionality with file support (#33)
- Added support for BinaryFiles in ExcalidrawData type. - Updated createNewPage and setDrawData functions to handle files. - Modified drawDataStore to include files in state management. - Enhanced Mermaid and Page components to manage file uploads and updates.
1 parent c5480e1 commit 9438a94

File tree

4 files changed

+50
-10
lines changed

4 files changed

+50
-10
lines changed

src/db/draw.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { NonDeletedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
2+
import { BinaryFiles } from "@excalidraw/excalidraw/types";
23
import { supabase } from "./supabase";
34
import { AuthError, PostgrestError } from "@supabase/supabase-js";
45

@@ -8,6 +9,12 @@ export type DBResponse = {
89
error: PostgrestError | AuthError | null;
910
};
1011

12+
export type ExcalidrawData = {
13+
elements: readonly NonDeletedExcalidrawElement[];
14+
appState?: Record<string, unknown>;
15+
files?: BinaryFiles;
16+
};
17+
1118
export const DB_NAME = "draw";
1219

1320
export async function getPages(user_id: string): Promise<DBResponse> {
@@ -32,12 +39,17 @@ export async function getDrawData(id: string): Promise<DBResponse> {
3239

3340
export async function createNewPage(
3441
elements?: readonly NonDeletedExcalidrawElement[],
42+
files?: BinaryFiles,
3543
): Promise<DBResponse> {
3644
const { data: profile, error: profileError } = await supabase.auth.getUser();
3745
if (profile) {
46+
const excalidrawData: ExcalidrawData = {
47+
elements: elements || [],
48+
files: files || {}
49+
};
3850
const { data, error } = await supabase
3951
.from(DB_NAME)
40-
.insert({ user_id: profile.user?.id, page_elements: { elements } })
52+
.insert({ user_id: profile.user?.id, page_elements: excalidrawData })
4153
.select();
4254
return { data, error };
4355
}
@@ -48,11 +60,16 @@ export async function setDrawData(
4860
id: string,
4961
elements: readonly NonDeletedExcalidrawElement[],
5062
name: string,
63+
files?: BinaryFiles,
5164
): Promise<DBResponse> {
5265
const updateTime = new Date().toISOString();
66+
const excalidrawData: ExcalidrawData = {
67+
elements,
68+
files: files || {}
69+
};
5370
const { data, error } = await supabase
5471
.from(DB_NAME)
55-
.update({ name: name, page_elements: { elements }, updated_at: updateTime })
72+
.update({ name: name, page_elements: excalidrawData, updated_at: updateTime })
5673
.eq("page_id", id)
5774
.select();
5875

src/stores/drawDataStore.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { NonDeletedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
2+
import { BinaryFiles } from "@excalidraw/excalidraw/types";
23
import { create } from "zustand";
34
import { persist } from "zustand/middleware";
45

@@ -7,6 +8,7 @@ export type DrawData = {
78
elements: readonly NonDeletedExcalidrawElement[];
89
updatedAt: string;
910
name: string;
11+
files?: BinaryFiles;
1012
};
1113
};
1214

@@ -17,6 +19,7 @@ type DrawDataStore = {
1719
elements: readonly NonDeletedExcalidrawElement[],
1820
updatedAt: string,
1921
name: string,
22+
files?: BinaryFiles,
2023
) => void;
2124
getPageData: (page_id: string) => DrawData[string] | undefined;
2225
};
@@ -25,7 +28,7 @@ const drawDataStore = create<DrawDataStore>()(
2528
persist(
2629
(set, get) => ({
2730
data: {},
28-
setPageData: (page_id, elements, updatedAt, name) =>
31+
setPageData: (page_id, elements, updatedAt, name, files) =>
2932
set((state) => {
3033
const currentData = state.data[page_id];
3134
if (
@@ -35,7 +38,7 @@ const drawDataStore = create<DrawDataStore>()(
3538
return {
3639
data: {
3740
...state.data,
38-
[page_id]: { elements, updatedAt, name },
41+
[page_id]: { elements, updatedAt, name, files },
3942
},
4043
};
4144
}

src/views/Mermaid.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export default function Mermaid() {
5858

5959
async function handleSaveAsNewPage() {
6060
const elements = excalidrawAPI?.getSceneElements();
61-
const data = await createNewPage(elements);
61+
const files = excalidrawAPI?.getFiles();
62+
const data = await createNewPage(elements, files);
6263

6364
if (data.data && data.data[0]?.page_id) {
6465
goToPage(data.data[0].page_id);

src/views/Page.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Input } from "@/components/ui/input";
1212
import { toast } from "sonner";
1313
import { Excalidraw, WelcomeScreen } from "@excalidraw/excalidraw";
1414
import { NonDeletedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
15-
import { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
15+
import { ExcalidrawImperativeAPI, BinaryFiles } from "@excalidraw/excalidraw/types";
1616
import { useQuery, useMutation } from "@tanstack/react-query";
1717
import { RefreshCcw } from "lucide-react";
1818
import { getDrawData, setDrawData } from "@/db/draw";
@@ -38,7 +38,8 @@ export default function Page({ id }: PageProps) {
3838
mutationFn: (data: {
3939
elements: NonDeletedExcalidrawElement[];
4040
name: string;
41-
}) => setDrawData(id, data.elements, data.name),
41+
files?: BinaryFiles;
42+
}) => setDrawData(id, data.elements, data.name, data.files),
4243
onSuccess: () => {
4344
setIsSaving(false);
4445
},
@@ -54,11 +55,20 @@ export default function Page({ id }: PageProps) {
5455

5556
async function updateScene() {
5657
if (data?.data && excalidrawAPI) {
57-
const elements = data.data[0].page_elements.elements;
58+
const pageData = data.data[0].page_elements;
59+
const elements = pageData.elements || [];
60+
const files = pageData.files || {};
61+
5862
excalidrawAPI.updateScene({
5963
elements: elements,
6064
appState: { theme: theme },
6165
});
66+
67+
// Update files if they exist
68+
if (Object.keys(files).length > 0) {
69+
excalidrawAPI.addFiles(Object.values(files));
70+
}
71+
6272
setName(data.data[0].name);
6373
}
6474
if (data?.error) {
@@ -69,20 +79,23 @@ export default function Page({ id }: PageProps) {
6979
const setSceneData = useCallback(async () => {
7080
if (excalidrawAPI) {
7181
const scene = excalidrawAPI.getSceneElements();
82+
const files = excalidrawAPI.getFiles();
7283
const updatedAt = new Date().toISOString();
7384

7485
const existingData = drawDataStore.getState().getPageData(id);
7586

76-
if (JSON.stringify(existingData?.elements) !== JSON.stringify(scene)) {
87+
if (JSON.stringify(existingData?.elements) !== JSON.stringify(scene) ||
88+
JSON.stringify(existingData?.files) !== JSON.stringify(files)) {
7789
setIsSaving(true);
7890
// Save locally first
79-
drawDataStore.getState().setPageData(id, scene, updatedAt, name);
91+
drawDataStore.getState().setPageData(id, scene, updatedAt, name, files);
8092

8193
// Then push to API
8294
mutate(
8395
{
8496
elements: scene as NonDeletedExcalidrawElement[],
8597
name,
98+
files,
8699
},
87100
{
88101
onSettled() {
@@ -117,6 +130,12 @@ export default function Page({ id }: PageProps) {
117130
elements: localData.elements,
118131
appState: { theme: theme },
119132
});
133+
134+
// Load files if they exist
135+
if (localData.files && Object.keys(localData.files).length > 0) {
136+
excalidrawAPI.addFiles(Object.values(localData.files));
137+
}
138+
120139
setName(localData.name);
121140
}
122141
}, [id, excalidrawAPI, theme]);

0 commit comments

Comments
 (0)