@riebeckite/plugin-excalidraw 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/README_ja.md +10 -0
- package/dist/index.js +118 -2
- package/dist/src/render.d.ts +6 -0
- package/package.json +6 -4
- package/style.css +19 -0
package/README.md
CHANGED
|
@@ -76,6 +76,23 @@ The following source is rendered as an SVG drawing on this page.
|
|
|
76
76
|
- Success → `data-excalidraw="ready"` (the SVG replaces the empty canvas)
|
|
77
77
|
- Failure → `data-excalidraw="error"` plus a placeholder message
|
|
78
78
|
|
|
79
|
+
## Standalone pages
|
|
80
|
+
|
|
81
|
+
An Excalidraw drawing stored as Markdown is also served as a standalone page
|
|
82
|
+
instead of a plain Markdown page. The plugin registers a page type
|
|
83
|
+
(`excalidraw-document`) that claims the entry's permalink with a trailing
|
|
84
|
+
`.excalidraw` removed.
|
|
85
|
+
|
|
86
|
+
- Detection: the slug ends in `.excalidraw` (for `*.excalidraw.md`), or the
|
|
87
|
+
frontmatter contains `excalidraw-plugin: parsed`
|
|
88
|
+
- `drawing.excalidraw.md` (permalink `/drawing.excalidraw`) is served at
|
|
89
|
+
`/drawing`
|
|
90
|
+
- The page body provides its own `<main>` and `<h1>`, and reuses the same
|
|
91
|
+
placeholder figure and `initExcalidraw` client as embedded wikilinks
|
|
92
|
+
|
|
93
|
+
The page type resolves before normal content routing, so no extra app route is
|
|
94
|
+
required. Only public entries are listed.
|
|
95
|
+
|
|
79
96
|
## Options
|
|
80
97
|
|
|
81
98
|
| Option | Type | Default | Description |
|
package/README_ja.md
CHANGED
|
@@ -48,6 +48,16 @@ export default defineConfig({
|
|
|
48
48
|
| --- | --- | --- | --- |
|
|
49
49
|
| `lazy` | `boolean` | `true` | 表示領域に近づいてから SVG を描画するか |
|
|
50
50
|
|
|
51
|
+
## 単体ページとしての表示
|
|
52
|
+
|
|
53
|
+
Excalidraw の描画である Markdown エントリは、通常の Markdown ページではなく専用ページとして表示されます。プラグインはページ型(`excalidraw-document`)を登録し、パーマリンク末尾の `.excalidraw` を除いたパスを引き受けます。
|
|
54
|
+
|
|
55
|
+
- 判定: slug が `.excalidraw` で終わる(`*.excalidraw.md`)、または frontmatter に `excalidraw-plugin: parsed` がある
|
|
56
|
+
- `drawing.excalidraw.md`(パーマリンク `/drawing.excalidraw`)は `/drawing` で表示される
|
|
57
|
+
- ページ本文は自前の `<main>` と `<h1>` を持ち、埋め込みウィキリンクと同じプレースホルダーと `initExcalidraw` を再利用する
|
|
58
|
+
|
|
59
|
+
ページ型は通常のコンテンツルーティングより先に解決されるため、アプリ側のルート追加は不要です。対象は公開エントリのみです。
|
|
60
|
+
|
|
51
61
|
## 公開 API
|
|
52
62
|
|
|
53
63
|
- `excalidraw(options?)` / `excalidrawPlugin` — プラグインファクトリ
|
package/dist/index.js
CHANGED
|
@@ -105,6 +105,17 @@ import {
|
|
|
105
105
|
escapeHtmlAttribute,
|
|
106
106
|
escapeScriptJson
|
|
107
107
|
} from "@riebeckite/core";
|
|
108
|
+
function renderExcalidrawPage(input) {
|
|
109
|
+
const heading = input.title ? `<h1 class="rr-excalidraw-page__title">${escapeHtml(input.title)}</h1>` : "";
|
|
110
|
+
return `<main class="rr-excalidraw-page">${heading}${renderExcalidrawPlaceholder(
|
|
111
|
+
{
|
|
112
|
+
title: input.title,
|
|
113
|
+
scene: input.scene,
|
|
114
|
+
lazy: input.lazy,
|
|
115
|
+
error: input.error
|
|
116
|
+
}
|
|
117
|
+
)}</main>`;
|
|
118
|
+
}
|
|
108
119
|
function renderExcalidrawPlaceholder(input) {
|
|
109
120
|
const style = renderSizeStyle(input.size);
|
|
110
121
|
const error = input.error ? `<p class="rr-excalidraw__error">${escapeHtml(input.error)}</p>` : "";
|
|
@@ -158,8 +169,24 @@ function excalidraw(options = {}) {
|
|
|
158
169
|
render: async (context) => renderAttachment(context, options)
|
|
159
170
|
}
|
|
160
171
|
],
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
pageTypes: [
|
|
173
|
+
{
|
|
174
|
+
id: "excalidraw-document",
|
|
175
|
+
paths: ({ manifest }) => listExcalidrawDocumentPaths(manifest),
|
|
176
|
+
outputDependencies: [{ type: "global" }],
|
|
177
|
+
resolve: (context) => resolveExcalidrawDocument(context, options)
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
assets: [
|
|
181
|
+
createStyleAsset(PLUGIN_NAME, "@riebeckite/plugin-excalidraw/style.css")
|
|
182
|
+
],
|
|
183
|
+
clientEntries: [
|
|
184
|
+
createClientEntry(
|
|
185
|
+
PLUGIN_NAME,
|
|
186
|
+
"@riebeckite/plugin-excalidraw/client",
|
|
187
|
+
"initExcalidraw"
|
|
188
|
+
)
|
|
189
|
+
]
|
|
163
190
|
});
|
|
164
191
|
}
|
|
165
192
|
var excalidrawPlugin = excalidraw;
|
|
@@ -211,6 +238,95 @@ function isExcalidrawDocument(filePath, raw) {
|
|
|
211
238
|
if (lowerPath.endsWith(".excalidraw.md")) return true;
|
|
212
239
|
return lowerPath.endsWith(".md") && isObsidianExcalidrawMarkdown(raw);
|
|
213
240
|
}
|
|
241
|
+
function listExcalidrawDocumentPaths(manifest) {
|
|
242
|
+
const paths = /* @__PURE__ */ new Set();
|
|
243
|
+
for (const entry of manifest.publicEntries) {
|
|
244
|
+
const path = getExcalidrawPagePath(entry);
|
|
245
|
+
if (path) paths.add(path);
|
|
246
|
+
}
|
|
247
|
+
return [...paths];
|
|
248
|
+
}
|
|
249
|
+
function isExcalidrawEntry(entry) {
|
|
250
|
+
if (entry.slug.toLowerCase().endsWith(".excalidraw")) return true;
|
|
251
|
+
return entry.frontmatter["excalidraw-plugin"] === "parsed";
|
|
252
|
+
}
|
|
253
|
+
function getExcalidrawPagePath(entry) {
|
|
254
|
+
if (!isExcalidrawEntry(entry)) return null;
|
|
255
|
+
const path = normalizePath(entry.permalink).replace(/\.excalidraw$/i, "");
|
|
256
|
+
if (!path || path === "/") return null;
|
|
257
|
+
if (/\.[a-zA-Z0-9]+$/.test(path.slice(1))) return null;
|
|
258
|
+
return path;
|
|
259
|
+
}
|
|
260
|
+
function findExcalidrawEntry(manifest, pathname) {
|
|
261
|
+
for (const entry of manifest.publicEntries) {
|
|
262
|
+
if (getExcalidrawPagePath(entry) === pathname) return entry;
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
async function resolveExcalidrawDocument(context, options) {
|
|
267
|
+
const entry = findExcalidrawEntry(context.manifest, context.pathname);
|
|
268
|
+
if (!entry) return null;
|
|
269
|
+
const title = resolveEntryTitle(entry);
|
|
270
|
+
const description = typeof entry.frontmatter.description === "string" ? entry.frontmatter.description : void 0;
|
|
271
|
+
const lazy = options.lazy !== false;
|
|
272
|
+
if (!context.contentSource) {
|
|
273
|
+
return {
|
|
274
|
+
type: "excalidraw-document",
|
|
275
|
+
pathname: context.pathname,
|
|
276
|
+
title,
|
|
277
|
+
description,
|
|
278
|
+
body: renderExcalidrawPage({
|
|
279
|
+
title,
|
|
280
|
+
lazy,
|
|
281
|
+
error: "Content source is not available."
|
|
282
|
+
})
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const sourcePath = `${entry.slug}.md`;
|
|
286
|
+
try {
|
|
287
|
+
const raw = await readText(context.contentSource, sourcePath);
|
|
288
|
+
if (raw === null) return null;
|
|
289
|
+
const parsed = parseExcalidrawScene(raw, sourcePath);
|
|
290
|
+
const scene = await mergeEmbeddedFiles({
|
|
291
|
+
scene: parsed.scene,
|
|
292
|
+
embeddedFiles: parsed.embeddedFiles,
|
|
293
|
+
contentSource: context.contentSource,
|
|
294
|
+
contentIndex: context.contentIndex
|
|
295
|
+
});
|
|
296
|
+
return {
|
|
297
|
+
type: "excalidraw-document",
|
|
298
|
+
pathname: context.pathname,
|
|
299
|
+
title,
|
|
300
|
+
description,
|
|
301
|
+
body: renderExcalidrawPage({ title, scene, lazy })
|
|
302
|
+
};
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error("[plugin-excalidraw] Failed to render Excalidraw page", {
|
|
305
|
+
path: sourcePath,
|
|
306
|
+
error
|
|
307
|
+
});
|
|
308
|
+
return {
|
|
309
|
+
type: "excalidraw-document",
|
|
310
|
+
pathname: context.pathname,
|
|
311
|
+
title,
|
|
312
|
+
description,
|
|
313
|
+
body: renderExcalidrawPage({
|
|
314
|
+
title,
|
|
315
|
+
lazy,
|
|
316
|
+
error: "Excalidraw could not be rendered."
|
|
317
|
+
})
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function resolveEntryTitle(entry) {
|
|
322
|
+
const trimmed = entry.title.trim().replace(/\.excalidraw$/i, "");
|
|
323
|
+
if (trimmed) return trimmed;
|
|
324
|
+
return getFileName(entry.slug).replace(/\.excalidraw$/i, "");
|
|
325
|
+
}
|
|
326
|
+
function normalizePath(pathname) {
|
|
327
|
+
const collapsed = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
328
|
+
return collapsed === "/" ? "/" : collapsed.replace(/\/+$/, "");
|
|
329
|
+
}
|
|
214
330
|
function parseSize(label) {
|
|
215
331
|
const value = label.trim();
|
|
216
332
|
if (/^\d{1,5}$/.test(value)) return { width: Number(value) };
|
package/dist/src/render.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { ExcalidrawScene } from "./types.js";
|
|
2
|
+
export declare function renderExcalidrawPage(input: {
|
|
3
|
+
title: string;
|
|
4
|
+
scene?: ExcalidrawScene;
|
|
5
|
+
lazy?: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
}): string;
|
|
2
8
|
export declare function renderExcalidrawPlaceholder(input: {
|
|
3
9
|
title: string;
|
|
4
10
|
scene?: ExcalidrawScene;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-excalidraw",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
"@excalidraw/excalidraw": "^0.18.0",
|
|
25
25
|
"lz-string": "^1.5.0",
|
|
26
26
|
"unist-util-visit": "^5.0.0",
|
|
27
|
-
"@riebeckite/core": "0.0.
|
|
27
|
+
"@riebeckite/core": "0.0.23"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/mdast": "^4.0.4"
|
|
30
|
+
"@types/mdast": "^4.0.4",
|
|
31
|
+
"tsx": "^4.22.4"
|
|
31
32
|
},
|
|
32
33
|
"publishConfig": {
|
|
33
34
|
"access": "public"
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"./style.css"
|
|
63
64
|
],
|
|
64
65
|
"scripts": {
|
|
65
|
-
"build": "node ../../../scripts/build_package.mjs"
|
|
66
|
+
"build": "node ../../../scripts/build_package.mjs",
|
|
67
|
+
"test": "node --import tsx --test \"test/*.test.ts\""
|
|
66
68
|
}
|
|
67
69
|
}
|
package/style.css
CHANGED
|
@@ -54,3 +54,22 @@
|
|
|
54
54
|
--rr-excalidraw-ink: var(--rb-color-paper, #ffffff);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
.rr-excalidraw-page {
|
|
59
|
+
width: min(100%, 96rem);
|
|
60
|
+
margin-inline: auto;
|
|
61
|
+
padding-inline: var(--rb-space-2, 1rem);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.rr-excalidraw-page__title {
|
|
65
|
+
margin: 0 0 var(--rb-space-2, 1rem);
|
|
66
|
+
font-family: var(--rb-font-heading, inherit);
|
|
67
|
+
font-size: clamp(1.75rem, 4vw, 2.75rem);
|
|
68
|
+
line-height: 1.05;
|
|
69
|
+
letter-spacing: -0.02em;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.rr-excalidraw-page .rr-excalidraw {
|
|
73
|
+
width: 100%;
|
|
74
|
+
margin: 0;
|
|
75
|
+
}
|