@lupinum/board-core 1.0.0-beta.4 → 1.0.0-beta.6
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/CHANGELOG.md +9 -0
- package/README.md +46 -25
- package/dist/agent/AGENTS.md +53 -57
- package/dist/agent/pages/docs/build-features/connections.md +333 -2
- package/dist/agent/pages/docs/build-features/custom-node-renderers.md +366 -2
- package/dist/agent/pages/docs/build-features/read-only-and-command-guards.md +278 -2
- package/dist/agent/pages/docs/build-features/save-and-load.md +264 -2
- package/dist/agent/pages/docs/build-features/selection-and-keyboard.md +257 -2
- package/dist/agent/pages/docs/build-features/theming.md +285 -2
- package/dist/agent/pages/docs/evaluate/how-nuxt-board-works.md +451 -2
- package/dist/agent/pages/docs/project/contributing.md +4 -4
- package/dist/agent/pages/docs/project/support-and-security.md +1 -1
- package/dist/agent/pages/docs/reference/events-and-errors.md +279 -2
- package/dist/agent/pages/docs/reference/package-overview.md +2 -2
- package/dist/agent/pages/docs/solutions/mind-map.md +448 -2
- package/dist/agent/pages/docs/solutions/nuxt-application.md +214 -2
- package/dist/agent/pages/docs/solutions/planning-board.md +281 -2
- package/dist/agent/pages/docs/solutions/read-only-viewer.md +278 -2
- package/dist/agent/pages/docs/solutions/workflow-builder.md +435 -2
- package/dist/agent/pages/docs/start-building/customize-your-first-node.md +381 -2
- package/dist/agent/pages/docs/start-building/installation.md +6 -14
- package/dist/agent/pages/docs/understand-the-system/commands-and-transactions.md +456 -2
- package/dist/agent/pages/docs/understand-the-system/document-and-session-state.md +348 -2
- package/dist/agent/pages/docs/understand-the-system/persistence-and-json-canvas.md +445 -2
- package/package.json +3 -2
- package/dist/agent/manifest.json +0 -320
|
@@ -15,8 +15,291 @@ source: "ginko-content"
|
|
|
15
15
|
|
|
16
16
|
Theme the board with CSS variables. Keep semantic state, such as node color presets, in engine state.
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
## Live example source
|
|
19
|
+
|
|
20
|
+
Use the installation guide to register @lupinum/nuxt-board. These are the actual documentation demo files. Keep their paths under app/. The module auto-imports Board components; install the optional packages named in imports. For the local content components, use components: [{ path: "~/components/content", pathPrefix: false }, "~/components"] in nuxt.config.ts, as this site does, or import them explicitly. createDemoDocument is a local helper, not a package export. DocsLab and the inspector components provide presentation only.
|
|
21
|
+
|
|
22
|
+
### app/components/demos/ThemePlayground.vue
|
|
23
|
+
|
|
24
|
+
````vue
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { computed, onMounted, reactive } from 'vue'
|
|
27
|
+
import { createBoardEngine } from '@lupinum/board-core'
|
|
28
|
+
import { createDemoDocument } from '../../utils/demoDocument'
|
|
29
|
+
|
|
30
|
+
const engine = createBoardEngine({
|
|
31
|
+
grid: { size: 20, majorEvery: 5, snap: true, pattern: 'dot' },
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const colors = reactive({
|
|
35
|
+
bg: '#f8fafc',
|
|
36
|
+
fg: '#0f172a',
|
|
37
|
+
nodeBg: '#ffffff',
|
|
38
|
+
nodeBorder: '#cbd5e1',
|
|
39
|
+
accent: '#0ea5e9',
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const boardStyle = computed(() => ({
|
|
43
|
+
'--board-bg': colors.bg,
|
|
44
|
+
'--board-fg': colors.fg,
|
|
45
|
+
'--board-node-bg': colors.nodeBg,
|
|
46
|
+
'--board-node-border': colors.nodeBorder,
|
|
47
|
+
'--board-node-stripe': `${colors.fg}14`,
|
|
48
|
+
'--board-accent': colors.accent,
|
|
49
|
+
'--board-handle-shadow': `${colors.fg}33`,
|
|
50
|
+
}))
|
|
51
|
+
|
|
52
|
+
function seed() {
|
|
53
|
+
engine.loadDocument(
|
|
54
|
+
createDemoDocument({
|
|
55
|
+
camera: { x: 0, y: 0, z: 1 },
|
|
56
|
+
grid: engine.getGridSettings(),
|
|
57
|
+
nodes: [
|
|
58
|
+
{
|
|
59
|
+
id: 'theme-1',
|
|
60
|
+
type: 'text',
|
|
61
|
+
x: 70,
|
|
62
|
+
y: 70,
|
|
63
|
+
width: 240,
|
|
64
|
+
height: 100,
|
|
65
|
+
text: 'Node',
|
|
66
|
+
zIndex: 1,
|
|
67
|
+
locked: false,
|
|
68
|
+
visible: true,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'theme-2',
|
|
72
|
+
type: 'text',
|
|
73
|
+
x: 370,
|
|
74
|
+
y: 190,
|
|
75
|
+
width: 240,
|
|
76
|
+
height: 100,
|
|
77
|
+
text: 'Node',
|
|
78
|
+
zIndex: 2,
|
|
79
|
+
locked: false,
|
|
80
|
+
visible: true,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
selection: [],
|
|
84
|
+
nextZIndex: 3,
|
|
85
|
+
}),
|
|
86
|
+
{ mode: 'replace' },
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function resetColors() {
|
|
91
|
+
colors.bg = '#f8fafc'
|
|
92
|
+
colors.fg = '#0f172a'
|
|
93
|
+
colors.nodeBg = '#ffffff'
|
|
94
|
+
colors.nodeBorder = '#cbd5e1'
|
|
95
|
+
colors.accent = '#0ea5e9'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function reset() {
|
|
99
|
+
seed()
|
|
100
|
+
resetColors()
|
|
101
|
+
await engine.zoomToFit(60, false)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
onMounted(reset)
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<template>
|
|
108
|
+
<div class="demo-frame">
|
|
109
|
+
<div class="demo-toolbar">
|
|
110
|
+
<button class="demo-danger" @click="reset">Reset theme</button>
|
|
111
|
+
<span class="demo-toolbar-note"
|
|
112
|
+
>Change the CSS custom properties and the board updates
|
|
113
|
+
immediately.</span
|
|
114
|
+
>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div class="grid gap-0 lg:grid-cols-[320px_minmax(0,1fr)]">
|
|
118
|
+
<div
|
|
119
|
+
class="border-b border-default bg-elevated p-4 lg:border-r lg:border-b-0"
|
|
120
|
+
>
|
|
121
|
+
<div class="space-y-4">
|
|
122
|
+
<label class="demo-color-field">
|
|
123
|
+
<div>
|
|
124
|
+
<span>Board background</span
|
|
125
|
+
><code class="demo-color-var">--board-bg</code>
|
|
126
|
+
</div>
|
|
127
|
+
<input v-model="colors.bg" type="color" />
|
|
128
|
+
</label>
|
|
129
|
+
<label class="demo-color-field">
|
|
130
|
+
<div>
|
|
131
|
+
<span>Board foreground</span
|
|
132
|
+
><code class="demo-color-var">--board-fg</code>
|
|
133
|
+
</div>
|
|
134
|
+
<input v-model="colors.fg" type="color" />
|
|
135
|
+
</label>
|
|
136
|
+
<label class="demo-color-field">
|
|
137
|
+
<div>
|
|
138
|
+
<span>Node background</span
|
|
139
|
+
><code class="demo-color-var">--board-node-bg</code>
|
|
140
|
+
</div>
|
|
141
|
+
<input v-model="colors.nodeBg" type="color" />
|
|
142
|
+
</label>
|
|
143
|
+
<label class="demo-color-field">
|
|
144
|
+
<div>
|
|
145
|
+
<span>Node border</span
|
|
146
|
+
><code class="demo-color-var">--board-node-border</code>
|
|
147
|
+
</div>
|
|
148
|
+
<input v-model="colors.nodeBorder" type="color" />
|
|
149
|
+
</label>
|
|
150
|
+
<label class="demo-color-field">
|
|
151
|
+
<div>
|
|
152
|
+
<span>Accent</span
|
|
153
|
+
><code class="demo-color-var">--board-accent</code>
|
|
154
|
+
</div>
|
|
155
|
+
<input v-model="colors.accent" type="color" />
|
|
156
|
+
</label>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="p-4">
|
|
161
|
+
<div
|
|
162
|
+
class="overflow-hidden rounded-md border border-default"
|
|
163
|
+
:style="boardStyle"
|
|
164
|
+
>
|
|
165
|
+
<BoardRoot
|
|
166
|
+
:engine="engine"
|
|
167
|
+
:grid="{ minorOpacity: 0.12, majorOpacity: 0.18, fadeEdges: true }"
|
|
168
|
+
style="height: 360px"
|
|
169
|
+
/>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</template>
|
|
175
|
+
````
|
|
176
|
+
|
|
177
|
+
### app/utils/demoDocument.ts
|
|
178
|
+
|
|
179
|
+
````ts
|
|
180
|
+
import type {
|
|
181
|
+
BoardNode,
|
|
182
|
+
BoardNodeMetadata,
|
|
183
|
+
Camera,
|
|
184
|
+
GridSettings,
|
|
185
|
+
JsonCanvasDocument,
|
|
186
|
+
JsonCanvasNode,
|
|
187
|
+
NodeId,
|
|
188
|
+
} from '@lupinum/board-core'
|
|
189
|
+
|
|
190
|
+
type DemoNode = Omit<
|
|
191
|
+
Pick<
|
|
192
|
+
BoardNode,
|
|
193
|
+
| 'id'
|
|
194
|
+
| 'type'
|
|
195
|
+
| 'x'
|
|
196
|
+
| 'y'
|
|
197
|
+
| 'width'
|
|
198
|
+
| 'height'
|
|
199
|
+
| 'color'
|
|
200
|
+
| 'text'
|
|
201
|
+
| 'file'
|
|
202
|
+
| 'subpath'
|
|
203
|
+
| 'url'
|
|
204
|
+
| 'label'
|
|
205
|
+
| 'background'
|
|
206
|
+
| 'backgroundStyle'
|
|
207
|
+
| 'zIndex'
|
|
208
|
+
| 'locked'
|
|
209
|
+
| 'visible'
|
|
210
|
+
| 'parentId'
|
|
211
|
+
>,
|
|
212
|
+
'id' | 'parentId'
|
|
213
|
+
> & {
|
|
214
|
+
id: NodeId | string
|
|
215
|
+
parentId?: NodeId | string
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface DemoDocumentInput {
|
|
219
|
+
nodes: readonly DemoNode[]
|
|
220
|
+
camera?: Camera
|
|
221
|
+
grid?: GridSettings
|
|
222
|
+
selection?: readonly (NodeId | string)[]
|
|
223
|
+
nextZIndex?: number
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function toJsonCanvasNode(node: DemoNode): JsonCanvasNode {
|
|
227
|
+
const base = {
|
|
228
|
+
id: node.id as NodeId,
|
|
229
|
+
type: node.type,
|
|
230
|
+
x: node.x,
|
|
231
|
+
y: node.y,
|
|
232
|
+
width: node.width,
|
|
233
|
+
height: node.height,
|
|
234
|
+
...(node.color ? { color: node.color } : {}),
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
switch (node.type) {
|
|
238
|
+
case 'file':
|
|
239
|
+
return {
|
|
240
|
+
...base,
|
|
241
|
+
type: 'file',
|
|
242
|
+
file: node.file ?? '',
|
|
243
|
+
...(node.subpath ? { subpath: node.subpath } : {}),
|
|
244
|
+
}
|
|
245
|
+
case 'link':
|
|
246
|
+
return {
|
|
247
|
+
...base,
|
|
248
|
+
type: 'link',
|
|
249
|
+
url: node.url ?? '',
|
|
250
|
+
}
|
|
251
|
+
case 'group':
|
|
252
|
+
return {
|
|
253
|
+
...base,
|
|
254
|
+
type: 'group',
|
|
255
|
+
...((node.label ?? node.text)
|
|
256
|
+
? { label: node.label ?? node.text }
|
|
257
|
+
: {}),
|
|
258
|
+
...(node.background ? { background: node.background } : {}),
|
|
259
|
+
...(node.backgroundStyle
|
|
260
|
+
? { backgroundStyle: node.backgroundStyle }
|
|
261
|
+
: {}),
|
|
262
|
+
}
|
|
263
|
+
case 'text':
|
|
264
|
+
default:
|
|
265
|
+
return {
|
|
266
|
+
...base,
|
|
267
|
+
type: 'text',
|
|
268
|
+
text: node.text ?? '',
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function toNodeMetadata(node: DemoNode): BoardNodeMetadata {
|
|
274
|
+
return {
|
|
275
|
+
zIndex: node.zIndex,
|
|
276
|
+
locked: node.locked,
|
|
277
|
+
visible: node.visible,
|
|
278
|
+
...(node.parentId ? { parentId: node.parentId as NodeId } : {}),
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function createDemoDocument(
|
|
283
|
+
input: DemoDocumentInput,
|
|
284
|
+
): JsonCanvasDocument {
|
|
285
|
+
return {
|
|
286
|
+
nodes: input.nodes.map(toJsonCanvasNode),
|
|
287
|
+
'x-lupinum-board': {
|
|
288
|
+
...(input.camera ? { camera: input.camera } : {}),
|
|
289
|
+
...(input.grid ? { grid: input.grid } : {}),
|
|
290
|
+
...(input.selection
|
|
291
|
+
? { selection: input.selection.map((id) => id as NodeId) }
|
|
292
|
+
: {}),
|
|
293
|
+
nextZIndex:
|
|
294
|
+
input.nextZIndex ??
|
|
295
|
+
input.nodes.reduce((max, node) => Math.max(max, node.zIndex), 0) + 1,
|
|
296
|
+
nodes: Object.fromEntries(
|
|
297
|
+
input.nodes.map((node) => [node.id, toNodeMetadata(node)]),
|
|
298
|
+
),
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
````
|
|
20
303
|
|
|
21
304
|
## Core tokens
|
|
22
305
|
|