Skip to content

Commit 223d2ea

Browse files
committed
Initial setup of Excalidraw Desktop Wrapper and self-hosted server. Added .gitignore, README, Dockerfile, and configuration files for Tauri app. Implemented basic app structure with URL validation and server connection functionality.
1 parent b101256 commit 223d2ea

File tree

18 files changed

+422
-1
lines changed

18 files changed

+422
-1
lines changed

.cursor/ndjson-ingest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"externalUrl": "http://127.0.0.1:64115/ingest",
3+
"logPath": "/Users/isaaclins/Documents/github/excalidraw-app/.cursor/debug.log"
4+
}

.github/workflows/release.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags: ["v*.*.*"]
6+
pull_request: {}
7+
8+
jobs:
9+
build:
10+
strategy:
11+
matrix:
12+
os: [ubuntu-latest, macos-latest, windows-latest]
13+
runs-on: ${{ matrix.os }}
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 20
19+
- uses: dtolnay/rust-toolchain@stable
20+
- name: Install Linux deps
21+
if: matrix.os == 'ubuntu-latest'
22+
run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
23+
- name: Install frontend deps
24+
run: cd app && npm ci
25+
- name: Run tests
26+
run: cd app && npm test --if-present
27+
- name: Build Tauri app
28+
uses: tauri-apps/tauri-action@v0
29+
env:
30+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules
2+
app/node_modules
3+
app/dist
4+
app/.DS_Store
5+
.DS_Store
6+
app/src-tauri/target
7+
app/src-tauri/.fingerprint
8+
app/src-tauri/Cargo.lock
9+
app/src-tauri/.cargo
10+
*.log

README.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,47 @@
1-
# excalidraw-app
1+
# Excalidraw Desktop Wrapper + Self-hosted Server (Render)
2+
3+
This repository contains:
4+
5+
- `app/`: A Tauri desktop app that opens a user-configured Excalidraw Server URL.
6+
- `server/`: A Dockerized self-hosted Excalidraw server suitable for Render with WebSockets for real-time collaboration.
7+
8+
## Quick Start (Desktop)
9+
10+
1. Install prerequisites: Node 20+, Rust (stable), Tauri deps.
11+
2. Install deps and run:
12+
13+
```bash
14+
cd app
15+
npm ci
16+
npm run dev
17+
```
18+
19+
3. Enter your deployed server URL (HTTPS) and click Save & Launch.
20+
21+
## Deploy the Server on Render
22+
23+
You can deploy the server in the `/server` directory using Render.
24+
25+
- Render will detect `render.yaml` at the repo root and build using `/server` as the root directory via `rootDir`.
26+
- After deployment, copy the service URL (e.g., `https://your-app.onrender.com`) into the desktop app.
27+
28+
### Manual steps on Render
29+
30+
1. New Web Service → Select this GitHub repo.
31+
2. Root Directory: `/server`.
32+
3. Runtime: Docker → `server/Dockerfile`.
33+
4. Environment:
34+
- `PORT=3000`
35+
- `STORAGE_TYPE=filesystem` (or `sqlite` / `s3`)
36+
- `STORAGE_PATH=/data`
37+
5. Add persistent disk: name `data`, mount `/data`, size `1GB`.
38+
6. Create service. Use the URL shown for the desktop app.
39+
40+
## CI (GitHub Actions)
41+
42+
Pushing a tag `v*.*.*` will build installers for Windows, macOS, and Linux and publish to GitHub Releases.
43+
44+
## Security Notes
45+
46+
- The app requires an HTTPS server URL and restricts Content Security Policy accordingly.
47+
- For small teams (2–5 users), `filesystem` or `sqlite` storage with a small disk is sufficient.

app/index.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Excalidraw Wrapper</title>
7+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; connect-src 'self' https: wss:; img-src 'self' data: https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" />
8+
</head>
9+
<body>
10+
<div id="app" style="max-width: 720px; margin: 40px auto; font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji';">
11+
<h1 style="margin: 0 0 16px;">Excalidraw Server URL</h1>
12+
<p style="color: #444; margin: 0 0 16px;">Enter the HTTPS URL of your self‑hosted Excalidraw server (Render).</p>
13+
<form id="settings-form" style="display: flex; gap: 8px; align-items: center;">
14+
<input id="serverUrl" type="url" placeholder="https://your-app.onrender.com" required style="flex: 1; padding: 10px 12px; border: 1px solid #ccc; border-radius: 6px;" />
15+
<button type="submit" style="padding: 10px 14px; border: 0; border-radius: 6px; background: #0ea5e9; color: #fff; cursor: pointer;">Save & Launch</button>
16+
</form>
17+
<button id="changeServer" style="margin-top: 10px; display: none; padding: 8px 12px; border-radius: 6px; border: 1px solid #ddd; background: #fafafa; cursor: pointer;">Change server</button>
18+
<p id="error" style="color: #b91c1c; margin-top: 12px;"></p>
19+
</div>
20+
<script type="module" src="/src/main.ts"></script>
21+
</body>
22+
</html>
23+
24+

app/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "excalidraw-wrapper",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview",
10+
"test": "vitest run"
11+
},
12+
"dependencies": {
13+
"@tauri-apps/api": "^2.0.0",
14+
"@tauri-apps/plugin-store": "^2.0.0"
15+
},
16+
"devDependencies": {
17+
"vitest": "^2.0.5",
18+
"typescript": "^5.6.3",
19+
"vite": "^5.4.0"
20+
}
21+
}
22+

app/src-tauri/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "excalidraw_wrapper"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
tauri = { version = "2", features = [] }
8+
tauri-plugin-store = "2"
9+
serde = { version = "1", features = ["derive"] }
10+
serde_json = "1"
11+
12+
[build-dependencies]
13+
tauri-build = { version = "2", features = [] }
14+
15+

app/src-tauri/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
tauri_build::build()
3+
}
4+
5+

app/src-tauri/src/main.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2+
3+
use tauri::{AppHandle, Manager, WebviewUrl, WebviewWindowBuilder};
4+
5+
#[tauri::command]
6+
async fn open_server_window(app: AppHandle, url: String) -> Result<(), String> {
7+
let label = "excalidraw";
8+
if let Some(existing) = app.get_webview_window(label) {
9+
let _ = existing.set_url(WebviewUrl::External(url.parse().map_err(|_| "invalid url")?));
10+
let _ = existing.set_focus();
11+
return Ok(());
12+
}
13+
14+
WebviewWindowBuilder::new(
15+
&app,
16+
label,
17+
WebviewUrl::External(url.parse().map_err(|_| "invalid url")?),
18+
)
19+
.title("Excalidraw")
20+
.build()
21+
.map_err(|e| e.to_string())?;
22+
23+
// Close settings window if present
24+
if let Some(settings) = app.get_webview_window("settings") {
25+
let _ = settings.close();
26+
}
27+
28+
Ok(())
29+
}
30+
31+
fn main() {
32+
tauri::Builder::default()
33+
.plugin(tauri_plugin_store::Builder::default().build())
34+
.invoke_handler(tauri::generate_handler![open_server_window])
35+
.run(tauri::generate_context!())
36+
.expect("error while running tauri application");
37+
}
38+
39+

app/src-tauri/tauri.conf.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/main/schemas/tauri.schema.json",
3+
"productName": "Excalidraw Wrapper",
4+
"version": "0.1.0",
5+
"identifier": "com.yourorg.excalidraw_wrapper",
6+
"build": {
7+
"frontendDist": "../dist",
8+
"devUrl": "http://localhost:5173"
9+
},
10+
"app": {
11+
"windows": [
12+
{
13+
"label": "settings",
14+
"title": "Excalidraw Server",
15+
"width": 720,
16+
"height": 420,
17+
"resizable": true,
18+
"fullscreen": false,
19+
"url": "/index.html",
20+
"useHttpsScheme": true
21+
}
22+
]
23+
},
24+
"security": {
25+
"csp": "default-src 'self'; connect-src 'self' https: wss:; img-src 'self' data: https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
26+
},
27+
"bundle": {
28+
"active": true,
29+
"targets": "all",
30+
"identifier": "com.yourorg.excalidraw_wrapper"
31+
}
32+
}
33+
34+

0 commit comments

Comments
 (0)