diff --git a/apps/api/src/plugins/plugin-frame.ts b/apps/api/src/plugins/plugin-frame.ts index 5242001..9e8e6b9 100644 --- a/apps/api/src/plugins/plugin-frame.ts +++ b/apps/api/src/plugins/plugin-frame.ts @@ -29,7 +29,10 @@ export function buildPluginFrameCsp(assetBase: string): string { `script-src ${assetBase}`, `style-src ${assetBase} 'unsafe-inline'`, `img-src ${assetBase} data: blob:`, - `font-src ${assetBase}`, + // `data:` so a saved sketch SVG with embedded (subsetted) fonts — the + // Excalidraw plugin stores those — renders its handwriting look in the + // snapshot view too. data: fonts make no network request. + `font-src ${assetBase} data:`, // A plugin may talk to its OWN version-pinned assets (bundled apps like // drawio lazy-load stencils/resources via XHR) — and to nothing else: // no api, no external hosts. The zero-external-network guarantee holds. diff --git a/apps/web/nginx.conf b/apps/web/nginx.conf index 0ea8184..c9c8b95 100644 --- a/apps/web/nginx.conf +++ b/apps/web/nginx.conf @@ -28,7 +28,11 @@ server { # from this origin only (the GDPR "zero external requests" posture). # `style-src 'unsafe-inline'` covers the app's inline style attributes # (CSS custom properties, layout); scripts are all external files. - add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always; + # font-src includes `data:` for the subsetted fonts Excalidraw embeds + # into saved sketch SVGs (inlined by the plugin fallback renderer on + # public pages). data: fonts trigger no network request, so the + # zero-third-party-request guarantee (security.md) is unaffected. + add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self'; manifest-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri /index.html; } diff --git a/docs/architecture/plugin-architecture.md b/docs/architecture/plugin-architecture.md index fd87cd8..d084dde 100644 --- a/docs/architecture/plugin-architecture.md +++ b/docs/architecture/plugin-architecture.md @@ -128,6 +128,12 @@ person looking at it could. build time into `vendor/`, gitignored) and runs fullscreen in the sandbox; blocks store `{ xml, svg }`, render mode and exports use the SVG snapshot. +- `excalidraw` (`block`): hand-drawn sketches — proves the npm-library + flavor of the bundled-app path: the Excalidraw React editor is bundled + straight into `plugin.js` (esbuild) with its font/locale assets shipped + alongside and loaded via `EXCALIDRAW_ASSET_PATH`; blocks store + `{ scene, svg }`, render mode and exports use the SVG snapshot (with + subsetted fonts embedded as `data:` URIs). These live in `packages/plugins/` in the monorepo, are built by CI, and double as the plugin-SDK integration tests. diff --git a/docs/de/developer/extending.md b/docs/de/developer/extending.md index 1eacdea..dd09b60 100644 --- a/docs/de/developer/extending.md +++ b/docs/de/developer/extending.md @@ -76,9 +76,13 @@ auszuführen. Ein Plugin darf eine ganze Unter-Anwendung als Assets mitbringen und in einem Kind-iframe seines eigenen Asset-Pfads ausführen — so bettet das -`drawio`-Plugin den echten draw.io-Editor ein. Kombiniere das mit -`host.ui.enterFullscreen()` für Editoren, die den ganzen Bildschirm -brauchen. Größen-Limits: 64 MiB ZIP, 256 MiB entpackt. +`drawio`-Plugin den echten draw.io-Editor ein. Das `excalidraw`-Plugin +zeigt die andere Spielart derselben Idee: eine npm-React-Bibliothek, +per esbuild direkt in die `plugin.js` gebündelt und im Frame selbst im +Vollbild gemountet, mit ihren Laufzeit-Assets (Fonts, Sprachen) im ZIP. +Kombiniere das mit `host.ui.enterFullscreen()` für Editoren, die den +ganzen Bildschirm brauchen. Größen-Limits: 64 MiB ZIP, 256 MiB +entpackt. ### Entwickeln und ausliefern diff --git a/docs/de/manual/site-admin-guide.md b/docs/de/manual/site-admin-guide.md index a6a0c48..e25d682 100644 --- a/docs/de/manual/site-admin-guide.md +++ b/docs/de/manual/site-admin-guide.md @@ -97,20 +97,22 @@ zeigen den Fallback-Text des Plugins, wenn es fehlt. Mitgelieferte Referenz-Plugins: `toc` (Inhaltsverzeichnis), `page-index` (label-gefilterte Seitenliste), `mermaid` (Diagramm-Blöcke), `drawio` (vollwertiges draw.io-Bearbeiten), -`section-styles-basic` (farbige Hinweiskästen). +`excalidraw` (handgezeichnete Skizzen), `section-styles-basic` +(farbige Hinweiskästen). **Woher kommen die ZIPs der Referenz-Plugins?** Sie liegen den Server-Images nicht bei — sie werden aus dem Repository gebaut (Node 22 und pnpm, einmalig `pnpm install` im Repo-Wurzelverzeichnis): ```sh -cd packages/plugins/ # toc | page-index | mermaid | drawio | section-styles-basic +cd packages/plugins/ # toc | page-index | mermaid | drawio | excalidraw | section-styles-basic pnpm build # → dist/-.zip — diese Datei hochladen ``` Der `drawio`-Build lädt beim ersten Lauf sein gepinntes Editor-Bundle von GitHub und packt ein ~27-MiB-ZIP (innerhalb des 64-MiB-Limits für -Plugin-Uploads); die anderen vier bauen offline in Sekunden. +Plugin-Uploads); `excalidraw` bündelt seinen Editor aus npm in ein +~16-MiB-ZIP; die übrigen vier bauen offline in Sekunden. **Typischer Ablauf:** ZIP hochladen, die abgeschottete Vorschau prüfen, den Instanz-Modus auf `optional` stellen und das Plugin dann je Teich diff --git a/docs/de/tutorial/18-bausteine.md b/docs/de/tutorial/18-bausteine.md index 59c822a..47a7fe5 100644 --- a/docs/de/tutorial/18-bausteine.md +++ b/docs/de/tutorial/18-bausteine.md @@ -38,7 +38,7 @@ anderen Seiten noch an deinem Konto etwas ändern. ## Ein Blick voraus -Dorfteich bringt fünf Standard-Plugins mit — von der Diagramm-Zeichnung +Dorfteich bringt sechs Standard-Plugins mit — von der Diagramm-Zeichnung bis zum automatischen Inhaltsverzeichnis. Die stellen wir im nächsten Kapitel einzeln vor, und du siehst sie dort auch in Nadias Teich im Einsatz. diff --git a/docs/de/tutorial/19-standard-bausteine.md b/docs/de/tutorial/19-standard-bausteine.md index dac4079..c992df6 100644 --- a/docs/de/tutorial/19-standard-bausteine.md +++ b/docs/de/tutorial/19-standard-bausteine.md @@ -1,9 +1,9 @@ # Die Standard-Bausteine im Schaufenster -Dorfteich bringt fünf Plugins mit. Dieses Kapitel ist ein +Dorfteich bringt sechs Plugins mit. Dieses Kapitel ist ein Schaufensterbummel: je ein Blick, wofür jeder Baustein gut ist — ohne -Bedienungsanleitung. (Die beiden Diagramm-Bausteine haben eigene kleine -Welten; hier geht es nur darum, dass du weißt, was es gibt.) +Bedienungsanleitung. (Die Diagramm- und Zeichen-Bausteine haben eigene +kleine Welten; hier geht es nur darum, dass du weißt, was es gibt.) ## Mermaid-Diagramm — Diagramme aus Text @@ -33,6 +33,19 @@ skizziert. ![Nadias Routen-Skizze aus dem draw.io-Baustein](img/19-drawio-gravel.png) +## Excalidraw — Skizzen wie von Hand + +Der dritte Zeichen-Baustein, und der lockerste: **Excalidraw** öffnet +sich ebenfalls im Vollbild, zeichnet aber im Handschrift-Look — Kästen +wirken hingeworfen, Beschriftungen wie mit dem Stift geschrieben. +Perfekt für schnelle Ideen, Lagepläne und alles, was bewusst nach +Entwurf aussehen soll statt nach fertigem Diagramm. + +Nadia hat damit auf ihrer Seite +[Konzerte & Live](https://dorfteich.online/public/nadia-morgenstern/konzerte-live) +den Bühnenplan fürs nächste Open-Air gekritzelt — samt Merker, wo der +beste Platz ist. + ## Inhaltsverzeichnis — lange Seiten gliedern Ein **Seiten-Werkzeug**: Es sitzt hinter dem Werkzeug-Symbol in der diff --git a/docs/developer/extending.md b/docs/developer/extending.md index 5e8b615..2a4cf5f 100644 --- a/docs/developer/extending.md +++ b/docs/developer/extending.md @@ -70,7 +70,10 @@ without ever executing plugin code. A plugin may ship an entire sub-application as assets and run it in a child iframe of its own asset path — that is how the `drawio` plugin -embeds the real draw.io editor. Combine with +embeds the real draw.io editor. The `excalidraw` plugin shows the other +flavor of the same idea: an npm React library bundled directly into +`plugin.js` (esbuild) and mounted fullscreen in the frame itself, with +its runtime assets (fonts, locales) shipped in the ZIP. Combine with `host.ui.enterFullscreen()` for editors that need the whole screen. Size limits: 64 MiB ZIP, 256 MiB unpacked. diff --git a/docs/manual/site-admin-guide.md b/docs/manual/site-admin-guide.md index b2a2bf6..d00100f 100644 --- a/docs/manual/site-admin-guide.md +++ b/docs/manual/site-admin-guide.md @@ -88,20 +88,22 @@ fallback text when it is missing. Shipped reference plugins: `toc` (table of contents), `page-index` (label-filtered page list), `mermaid` (diagram blocks), `drawio` -(full draw.io editing), `section-styles-basic` (colored callouts). +(full draw.io editing), `excalidraw` (hand-drawn sketches), +`section-styles-basic` (colored callouts). **Getting the reference plugin ZIPs.** They are not bundled with the server images — build them from the repository (Node 22 + pnpm, one-time `pnpm install` at the repo root): ```sh -cd packages/plugins/ # toc | page-index | mermaid | drawio | section-styles-basic +cd packages/plugins/ # toc | page-index | mermaid | drawio | excalidraw | section-styles-basic pnpm build # → dist/-.zip — upload that file ``` The `drawio` build downloads its pinned editor bundle from GitHub on the first run and packs a ~27 MiB ZIP (within the 64 MiB plugin upload -limit); the other four build offline in seconds. +limit); `excalidraw` bundles its editor from npm into a ~16 MiB ZIP; the +remaining four build offline in seconds. **Typical rollout:** upload the ZIP, check the sandboxed preview, switch the instance mode to `optional`, then enable the plugin per pond (pond diff --git a/packages/shared/src/fonts.ts b/packages/shared/src/fonts.ts index e36e654..9cbf82e 100644 --- a/packages/shared/src/fonts.ts +++ b/packages/shared/src/fonts.ts @@ -5,9 +5,10 @@ * page lists their licenses. Adding a font is a change here + an image rebuild * — there is no runtime font management (deliberately small surface). * - * Fonts are served only from the instance itself (`font-src 'self'`); a - * visitor's browser makes zero third-party requests (the GDPR guarantee, - * security.md). + * Fonts are served only from the instance itself (`font-src 'self' data:` — + * the `data:` part covers fonts embedded inline in saved plugin SVGs, e.g. + * Excalidraw sketches); a visitor's browser makes zero third-party requests + * (the GDPR guarantee, security.md). */ export type FontCategory = 'sans-serif' | 'serif' | 'monospace'; export type FontLicense = 'OFL-1.1' | 'Apache-2.0';