([]);
+
+ usePartySocket({
+ host: window.location.host,
+ room: "room-1",
+ party: "chat",
+ onMessage(event) {
+ const data: FromServerSocketMessage = JSON.parse(event.data);
+ switch (data.type) {
+ case "svg_uploaded":
+ setImages((prev) => [...prev, data.svgPath]);
+ break;
+ }
+ },
+ });
+
return (
Welcome Home!
+
+ {images.map((image, index) => (
+ -
+
+
+ ))}
+
);
diff --git a/client-src/views/draw/constants/constants.ts b/client-src/views/draw/constants/constants.ts
index 7699413..4db8f1a 100644
--- a/client-src/views/draw/constants/constants.ts
+++ b/client-src/views/draw/constants/constants.ts
@@ -3,5 +3,5 @@ import { PartySocket } from "partysocket";
export const socket = new PartySocket({
host: window.location.host,
party: "chat",
- room: "test"
+ room: "room-1"
});
diff --git a/client-src/views/draw/draw-page.tsx b/client-src/views/draw/draw-page.tsx
deleted file mode 100644
index b9f89d9..0000000
--- a/client-src/views/draw/draw-page.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { Editor } from "./components/editor";
-import { Controls } from "./components/controls";
-import { useKeyboardShortcuts } from "./hooks";
-import { app } from "./state";
-import { socketSend } from "./services/socket";
-
-export function DrawPage() {
- useKeyboardShortcuts();
-
- return (
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/client-src/views/room/UserToolbar.tsx b/client-src/views/room/UserToolbar.tsx
index 8005fc3..0969973 100644
--- a/client-src/views/room/UserToolbar.tsx
+++ b/client-src/views/room/UserToolbar.tsx
@@ -1,6 +1,8 @@
import { useState } from "react";
import { Controls } from "../draw/components/controls";
import { Editor } from "../draw/components/editor";
+import { socketSend } from "../draw/services/socket";
+import { app } from "../draw/state";
export default function UserToolbar() {
const [name, setName] = useState("frogboi");
@@ -12,14 +14,14 @@ export default function UserToolbar() {
- setName(e.currentTarget.value)}
- className="text-lg text-center w-fit border-2 border-green-800 bg-white font-bold rounded pl-2"
+ className="text-lg text-center w-fit border-2 border-green-800 bg-white font-bold rounded pl-2"
/>
-
+
@@ -29,7 +31,11 @@ export default function UserToolbar() {
-
+
diff --git a/isomophic-src/isomorphic.ts b/isomophic-src/isomorphic.ts
index be3085a..7680160 100644
--- a/isomophic-src/isomorphic.ts
+++ b/isomophic-src/isomorphic.ts
@@ -12,10 +12,14 @@ export const FromClientSocketMessageSchema = z.union([
export type FromClientSocketMessage = z.infer;
-// The type of messages sent from the server to the client via WebSocket
-export const FromServerSocketMessageSchema = z.object({
- type: z.literal("acknowledge"),
- message: z.string(),
+const SVGUploadedSchema = z.object({
+ type: z.literal("svg_uploaded"),
+ svgPath: z.string(),
});
+// The type of messages sent from the server to the client via WebSocket
+export const FromServerSocketMessageSchema = z.union([
+ SVGUploadedSchema,
+]);
+
export type FromServerSocketMessage = z.infer;
\ No newline at end of file
diff --git a/package.json b/package.json
index 303cca5..af6c660 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
"build": "tsc && vite build",
"lint": "eslint .",
"preview": "vite preview",
- "format": "prettier --write ."
+ "format": "prettier --write .",
+ "gen:wrangler:types": "wrangler types"
},
"dependencies": {
"@modulz/radix-icons": "^4.0.0",
diff --git a/server-src/server.ts b/server-src/server.ts
index 035897f..13fb968 100644
--- a/server-src/server.ts
+++ b/server-src/server.ts
@@ -17,13 +17,19 @@ export class Chat extends Server {
switch (data.type) {
case "upload-svg": {
- await this.ctx.storage.put("value", '123');
+ const svgContent = data.svg;
- const val = await this.ctx.storage.get("value");
+ const svgFileName = `drawing-${crypto.randomUUID()}.svg`;
+
+ await (this.env as Cloudflare.Env).DRAWINGS_BUCKET.put(svgFileName, svgContent, {
+ httpMetadata: {
+ contentType: "image/svg+xml",
+ },
+ });
this.broadcast(getMessageForClient({
- type: "acknowledge",
- message: `SVG received and stored with value: ${val}`,
+ type: "svg_uploaded",
+ svgPath: `https://drawings.tadpole.social/${svgFileName}`,
}));
break;
}
diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts
index 25ede53..910daae 100644
--- a/worker-configuration.d.ts
+++ b/worker-configuration.d.ts
@@ -1,5 +1,5 @@
/* eslint-disable */
-// Generated by Wrangler by running `wrangler types` (hash: 312235bc59d50703278e9ebbb16915d4)
+// Generated by Wrangler by running `wrangler types` (hash: b867445971fae1bd36cd3546834ddd85)
// Runtime types generated with workerd@1.20251109.0 2025-11-05
declare namespace Cloudflare {
interface GlobalProps {
@@ -8,6 +8,7 @@ declare namespace Cloudflare {
}
interface Env {
Chat: DurableObjectNamespace;
+ DRAWINGS_BUCKET: R2Bucket;
}
}
interface Env extends Cloudflare.Env {}
diff --git a/wrangler.toml b/wrangler.toml
index 973ff10..f03b351 100644
--- a/wrangler.toml
+++ b/wrangler.toml
@@ -13,3 +13,8 @@ class_name = "Chat"
[[migrations]]
tag = "v1" # Should be unique for each entry
new_sqlite_classes = ["Chat"]
+
+[[r2_buckets]]
+binding = 'DRAWINGS_BUCKET' # <~ valid JavaScript variable name
+bucket_name = 'drawings'
+remote = true