batman
This commit is contained in:
commit
6860ab45cc
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/*
|
||||||
|
client/node_modules/*
|
||||||
|
package-lock.json
|
||||||
13
client/index.html
Normal file
13
client/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=2.0,user-scalable=no" />
|
||||||
|
<title>Excalidraw App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/index.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
15
client/package.json
Normal file
15
client/package.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@excalidraw/excalidraw": "^0.17.6",
|
||||||
|
"@solidjs/router": "^0.6.0",
|
||||||
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"solid-js": "^1.7.0",
|
||||||
|
"solid-react-compat": "^0.0.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "vite build",
|
||||||
|
"dev": "vite dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
client/src/index.jsx
Normal file
16
client/src/index.jsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { render } from "solid-js/web";
|
||||||
|
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1 style={{ textAlign: "center" }}>Excalidraw Example</h1>
|
||||||
|
<div style={{ height: "500px" }}>
|
||||||
|
<Excalidraw />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(() => <App />, document.getElementById("root"));
|
||||||
|
|
||||||
19
client/src/initExcalidraw.js
Normal file
19
client/src/initExcalidraw.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// src/initExcalidraw.js
|
||||||
|
// Helper to initialize Excalidraw in a SolidJS environment.
|
||||||
|
// We import the necessary modules from 'excalidraw' and create the editor.
|
||||||
|
import { initializeApp, importFromLocalStorage } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
|
export async function initializeExcalidraw(container, { initialData }) {
|
||||||
|
// In a real scenario, you'd use the official Excalidraw package API.
|
||||||
|
// The pseudo code below assumes a function `initializeApp` that returns { app, api }.
|
||||||
|
// Check Excalidraw docs for actual integration steps.
|
||||||
|
|
||||||
|
const { app, api } = await initializeApp({
|
||||||
|
target: container,
|
||||||
|
// initialData may be: { elements, appState, ... }
|
||||||
|
initialData: initialData || {},
|
||||||
|
UIOptions: { dockedSidebar: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
7
client/vite.config.js
Normal file
7
client/vite.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// vite.config.js
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
import react from "@vitejs/plugin-react";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
});
|
||||||
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^6.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
68
server/cmd/main.go
Normal file
68
server/cmd/main.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// main.go
|
||||||
|
// (Run: go build && ./yourapp)
|
||||||
|
// This server serves the static files for the client from "./public"
|
||||||
|
// and provides endpoints to load/save a single .excalidraw file.
|
||||||
|
//
|
||||||
|
// Make sure to create a "public" folder and build the SolidJS client into it.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const stateFile = "drawing.excalidraw"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.Handle("/", http.FileServer(http.Dir("public")))
|
||||||
|
|
||||||
|
http.HandleFunc("/api/state", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||||
|
|
||||||
|
if r.Method == http.MethodOptions {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
data, err := os.ReadFile(stateFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("No file yet or error reading file:", err)
|
||||||
|
// If no file yet, return empty object
|
||||||
|
w.Write([]byte(`{}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(data)
|
||||||
|
return
|
||||||
|
} else if r.Method == http.MethodPost {
|
||||||
|
log.Println("POST /api/state")
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "cannot read body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Validate JSON
|
||||||
|
var js interface{}
|
||||||
|
if err := json.Unmarshal(body, &js); err != nil {
|
||||||
|
http.Error(w, "invalid json", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(stateFile, body, 0644); err != nil {
|
||||||
|
http.Error(w, "cannot save file", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Println("Server running on http://localhost:8080")
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
1
server/drawing.excalidraw
Normal file
1
server/drawing.excalidraw
Normal file
File diff suppressed because one or more lines are too long
21
server/public/index.html
Normal file
21
server/public/index.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Excalidraw in browser</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script src="https://unpkg.com/react@18.2.0/umd/react.development.js"></script>
|
||||||
|
<script src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js"></script>
|
||||||
|
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="https://unpkg.com/@excalidraw/excalidraw/dist/excalidraw.development.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div id="app"></div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="packages/excalidraw/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
57
server/public/packages/excalidraw/index.js
Normal file
57
server/public/packages/excalidraw/index.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// public/packages/excalidraw/index.js
|
||||||
|
// This version fetches initial data from /api/state and saves changes back.
|
||||||
|
// Make sure your Go server (from previous snippets) is running and serving /api/state.
|
||||||
|
// Assumes a simple backend that returns/accepts JSON of the Excalidraw file.
|
||||||
|
|
||||||
|
const { useState, useEffect } = React;
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [initialData, setInitialData] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch("/api/state")
|
||||||
|
.then((res) => {
|
||||||
|
console.log("Fetch response:", res);
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
console.log("Fetched data:", data);
|
||||||
|
setInitialData(data);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error loading initial data:", err);
|
||||||
|
setInitialData({});
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleChange = (elements, appState) => {
|
||||||
|
const data = {
|
||||||
|
type: "excalidraw",
|
||||||
|
version: 2,
|
||||||
|
source: "excalidraw",
|
||||||
|
elements: elements,
|
||||||
|
appState: appState,
|
||||||
|
files: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch("/api/state", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
}).catch(console.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
return React.createElement(
|
||||||
|
"div",
|
||||||
|
{ style: { height: "100vh" } },
|
||||||
|
initialData &&
|
||||||
|
React.createElement(ExcalidrawLib.Excalidraw, {
|
||||||
|
initialData: initialData,
|
||||||
|
onChange: handleChange,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const excalidrawWrapper = document.getElementById("app");
|
||||||
|
const root = ReactDOM.createRoot(excalidrawWrapper);
|
||||||
|
root.render(React.createElement(App));
|
||||||
Loading…
Reference in New Issue
Block a user