@almadar/std 16.183.0 → 16.184.0
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/behaviors/lolo/ui/core/.hand-authored.json +4 -0
- package/behaviors/lolo/ui/core/atoms/std-browse.lolo +11 -0
- package/behaviors/lolo/ui/core/atoms/std-related.lolo +86 -9
- package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +115 -1
- package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +62 -2
- package/behaviors/lolo/ui/core/atoms/std-thread.lolo +43 -2
- package/behaviors/lolo/ui/core/atoms/std-tree.lolo +247 -0
- package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +110 -2
- package/behaviors/lolo/ui/core/molecules/ui-file-tree.lolo +18 -2
- package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +6 -2
- package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +2 -2
- package/behaviors/lolo/ui/core/organisms/ui-form.lolo +2 -2
- package/behaviors/lolo/ui/game/atoms/std-tutorial-autodemo.lolo +136 -0
- package/behaviors/lolo/ui/game/atoms/std-tutorial-overlay.lolo +41 -8
- package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +3 -3
- package/behaviors/registry/ui/core/atoms/std-browse.orb +17 -0
- package/behaviors/registry/ui/core/atoms/std-related.orb +256 -3
- package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +407 -1
- package/behaviors/registry/ui/core/atoms/std-tag-taxonomy.orb +240 -8
- package/behaviors/registry/ui/core/atoms/std-thread.orb +254 -4
- package/behaviors/registry/ui/core/atoms/std-tree.orb +656 -0
- package/behaviors/registry/ui/core/atoms/std-version-history.orb +479 -6
- package/behaviors/registry/ui/core/molecules/ui-file-tree.orb +43 -19
- package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +28 -3
- package/behaviors/registry/ui/core/organisms/ui-form-section.orb +8 -2
- package/behaviors/registry/ui/core/organisms/ui-form.orb +8 -2
- package/behaviors/registry/ui/game/atoms/std-tutorial-autodemo.orb +732 -0
- package/behaviors/registry/ui/game/atoms/std-tutorial-overlay.orb +305 -153
- package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +26 -0
- package/dist/behaviors/exports-reader.js +4320 -2060
- package/dist/behaviors/functions/index.d.ts +259 -44
- package/dist/behaviors/functions/index.js +4306 -2058
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +4321 -2061
- package/dist/behaviors/query.js +4320 -2060
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +274 -266
- package/dist/behaviors-registry.json +820 -33
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4321 -2061
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/package.json +2 -2
|
@@ -151,6 +151,10 @@
|
|
|
151
151
|
"signature": "a923f3042436663f",
|
|
152
152
|
"board": "packages/almadar-std/behaviors/lolo/ui/core/atoms/std-thread.lolo"
|
|
153
153
|
},
|
|
154
|
+
"std-tree": {
|
|
155
|
+
"signature": "",
|
|
156
|
+
"board": "packages/almadar-std/behaviors/lolo/ui/core/atoms/std-tree.lolo"
|
|
157
|
+
},
|
|
154
158
|
"std-version-history": {
|
|
155
159
|
"signature": "1f1eb4fcabd6cead",
|
|
156
160
|
"board": "packages/almadar-std/behaviors/lolo/ui/core/atoms/std-version-history.lolo"
|
|
@@ -84,6 +84,7 @@ orbital BrowseItemOrbital {
|
|
|
84
84
|
(fetch BrowseItem {
|
|
85
85
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
86
86
|
filter: (and (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id]) (or ["=", @config.initialFilterField, ""] ["=", (object/get @entity @config.initialFilterField), @config.initialFilterValue]))
|
|
87
|
+
include: @config.include
|
|
87
88
|
limit: @config.pageSize
|
|
88
89
|
offset: 0
|
|
89
90
|
})
|
|
@@ -113,6 +114,7 @@ orbital BrowseItemOrbital {
|
|
|
113
114
|
(fetch BrowseItem {
|
|
114
115
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
115
116
|
filter: (and (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id]) (or ["=", @config.initialFilterField, ""] ["=", (object/get @entity @config.initialFilterField), @config.initialFilterValue]))
|
|
117
|
+
include: @config.include
|
|
116
118
|
limit: @config.pageSize
|
|
117
119
|
offset: 0
|
|
118
120
|
})
|
|
@@ -126,6 +128,7 @@ orbital BrowseItemOrbital {
|
|
|
126
128
|
(fetch BrowseItem {
|
|
127
129
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
128
130
|
filter: (and (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id]) (or ["=", ?searchTerm, ""] (str/includes (object/get @entity name) ?searchTerm)))
|
|
131
|
+
include: @config.include
|
|
129
132
|
limit: @config.pageSize
|
|
130
133
|
offset: 0
|
|
131
134
|
})
|
|
@@ -133,6 +136,7 @@ orbital BrowseItemOrbital {
|
|
|
133
136
|
(fetch BrowseItem {
|
|
134
137
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
135
138
|
filter: (and (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id]) (or ["=", ?value, ""] ["=", (object/get @entity ?field), ?value]))
|
|
139
|
+
include: @config.include
|
|
136
140
|
limit: @config.pageSize
|
|
137
141
|
offset: 0
|
|
138
142
|
})
|
|
@@ -140,6 +144,7 @@ orbital BrowseItemOrbital {
|
|
|
140
144
|
(fetch BrowseItem {
|
|
141
145
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
142
146
|
filter: (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id])
|
|
147
|
+
include: @config.include
|
|
143
148
|
limit: @config.pageSize
|
|
144
149
|
offset: ["*", ["-", ?page, 1], @config.pageSize]
|
|
145
150
|
})
|
|
@@ -170,6 +175,7 @@ orbital BrowseItemOrbital {
|
|
|
170
175
|
(fetch BrowseItem {
|
|
171
176
|
emit: { failure: BrowseItemLoadFailed, success: BrowseItemLoaded }
|
|
172
177
|
filter: (and (or ["=", @config.scopeField, ""] ["=", (object/get @entity @config.scopeField), @user.id]) (or ["=", @config.initialFilterField, ""] ["=", (object/get @entity @config.initialFilterField), @config.initialFilterValue]))
|
|
178
|
+
include: @config.include
|
|
173
179
|
limit: @config.pageSize
|
|
174
180
|
offset: 0
|
|
175
181
|
})
|
|
@@ -346,6 +352,11 @@ orbital BrowseItemOrbital {
|
|
|
346
352
|
@description "Rows visible per page before the pagination control appears."
|
|
347
353
|
@synonyms "visible rows, items per page, display limit, show per page"
|
|
348
354
|
@tier "presentation"
|
|
355
|
+
include : [string] = []
|
|
356
|
+
@label "Which relation fields to hydrate?"
|
|
357
|
+
@description "Entity relation field names to hydrate on fetch (e.g. a `tag : Category` field named `tag`), so grid columns can use dot-paths like tag.name. Empty = no hydration, the default."
|
|
358
|
+
@synonyms "relation hydration, populate relations, joined fields, hydrate relations"
|
|
359
|
+
@tier "internal"
|
|
349
360
|
filters : [FilterSpec] = []
|
|
350
361
|
@label "Which filters should appear above the list?"
|
|
351
362
|
@description "Dropdown filter facets by field. Each fires a refetch when the user changes the selection. Empty = no filter bar."
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
app std-related "1.
|
|
1
|
+
app std-related "1.1.0"
|
|
2
2
|
"std-related as a Function"
|
|
3
3
|
;;
|
|
4
|
-
;; Relation-rendering atom.
|
|
5
|
-
;;
|
|
6
|
-
;;
|
|
4
|
+
;; Relation-rendering atom. INIT loads the full RelatedItem collection
|
|
5
|
+
;; unfiltered (unchanged default). A consumer that wants the list scoped to
|
|
6
|
+
;; one parent document sets `relationField` (the RelatedItem column that
|
|
7
|
+
;; holds the parent key) and redirects its own "document opened" signal to
|
|
8
|
+
;; SHOW_RELATED { key } in a `listens` override — the atom then fetches only
|
|
9
|
+
;; rows whose relationField equals key. Each row is clickable: it emits
|
|
10
|
+
;; SELECT_RELATED { id, name } for a parent molecule (e.g.
|
|
11
|
+
;; std-related-master-detail) to drive a detail panel.
|
|
7
12
|
;;
|
|
8
13
|
;; Paired with std-browse via @trait.X this gives a one-line master-detail
|
|
9
|
-
;; layout: hstack [ @trait.ParentList, @trait.ParentRelated ].
|
|
10
|
-
;; std-related-master-detail is the canonical showcase.
|
|
14
|
+
;; layout: hstack [ @trait.ParentList, @trait.ParentRelated ].
|
|
11
15
|
orbital RelatedItemOrbital {
|
|
12
16
|
type RelatedItemLoaded = Event { data : [RelatedItem] } "Fired when RelatedItem finishes loading; payload.data holds the list"
|
|
13
17
|
|
|
14
18
|
type RelatedItemLoadFailed = Event { error : string, code : string } "Fired when RelatedItem fails to load"
|
|
15
19
|
|
|
20
|
+
type ShowRelated = Event { key : string! } "Fired to scope the related fetch to rows whose relationField equals key"
|
|
21
|
+
|
|
16
22
|
entity RelatedItem [persistent: relateditems] {
|
|
17
23
|
id : string!
|
|
18
24
|
name : string @description "The identifier or designation for the related item." @synonyms "title, label, identifier"
|
|
@@ -39,12 +45,30 @@ orbital RelatedItemOrbital {
|
|
|
39
45
|
gap: sm
|
|
40
46
|
type: stack
|
|
41
47
|
})
|
|
48
|
+
SHOW_RELATED -> loading
|
|
49
|
+
(fetch RelatedItem {
|
|
50
|
+
emit: { failure: RelatedItemLoadFailed, success: RelatedItemLoaded }
|
|
51
|
+
filter: (or ["=", @config.relationField, ""] ["=", (object/get @entity @config.relationField), ?key])
|
|
52
|
+
})
|
|
53
|
+
(render-ui main {
|
|
54
|
+
align: center
|
|
55
|
+
children: [{ type: spinner }, {
|
|
56
|
+
color: muted
|
|
57
|
+
content: "Loading related…"
|
|
58
|
+
type: typography
|
|
59
|
+
variant: caption
|
|
60
|
+
}]
|
|
61
|
+
className: py-8
|
|
62
|
+
direction: vertical
|
|
63
|
+
gap: sm
|
|
64
|
+
type: stack
|
|
65
|
+
})
|
|
42
66
|
RelatedItemLoaded -> loaded
|
|
43
67
|
(render-ui main {
|
|
44
68
|
children: [{
|
|
45
69
|
align: center
|
|
46
70
|
children: [{ name: link, type: icon }, {
|
|
47
|
-
content:
|
|
71
|
+
content: @config.title
|
|
48
72
|
type: typography
|
|
49
73
|
variant: h3
|
|
50
74
|
}]
|
|
@@ -56,13 +80,23 @@ orbital RelatedItemOrbital {
|
|
|
56
80
|
fields: []
|
|
57
81
|
look: @config.tableLook
|
|
58
82
|
renderItem: (fn item {
|
|
83
|
+
align: center
|
|
59
84
|
children: [{
|
|
60
85
|
content: @item.name
|
|
61
86
|
type: typography
|
|
62
87
|
variant: body
|
|
88
|
+
}, {
|
|
89
|
+
action: SELECT_RELATED
|
|
90
|
+
actionPayload: { id: @item.id, name: @item.name }
|
|
91
|
+
icon: chevron-right
|
|
92
|
+
label: Open
|
|
93
|
+
size: sm
|
|
94
|
+
type: button
|
|
95
|
+
variant: ghost
|
|
63
96
|
}]
|
|
64
|
-
direction:
|
|
97
|
+
direction: horizontal
|
|
65
98
|
gap: xs
|
|
99
|
+
justify: between
|
|
66
100
|
type: stack
|
|
67
101
|
})
|
|
68
102
|
type: data-list
|
|
@@ -107,6 +141,14 @@ orbital RelatedItemOrbital {
|
|
|
107
141
|
emit: { failure: RelatedItemLoadFailed, success: RelatedItemLoaded }
|
|
108
142
|
})
|
|
109
143
|
(render-ui main { type: spinner })
|
|
144
|
+
SELECT_RELATED -> loaded
|
|
145
|
+
(set @entity.id ?id)
|
|
146
|
+
SHOW_RELATED -> loading
|
|
147
|
+
(fetch RelatedItem {
|
|
148
|
+
emit: { failure: RelatedItemLoadFailed, success: RelatedItemLoaded }
|
|
149
|
+
filter: (or ["=", @config.relationField, ""] ["=", (object/get @entity @config.relationField), ?key])
|
|
150
|
+
})
|
|
151
|
+
(render-ui main { type: spinner })
|
|
110
152
|
}
|
|
111
153
|
|
|
112
154
|
state error {
|
|
@@ -122,6 +164,12 @@ orbital RelatedItemOrbital {
|
|
|
122
164
|
emit: { failure: RelatedItemLoadFailed, success: RelatedItemLoaded }
|
|
123
165
|
})
|
|
124
166
|
(render-ui main { type: spinner })
|
|
167
|
+
SHOW_RELATED -> loading
|
|
168
|
+
(fetch RelatedItem {
|
|
169
|
+
emit: { failure: RelatedItemLoadFailed, success: RelatedItemLoaded }
|
|
170
|
+
filter: (or ["=", @config.relationField, ""] ["=", (object/get @entity @config.relationField), ?key])
|
|
171
|
+
})
|
|
172
|
+
(render-ui main { type: spinner })
|
|
125
173
|
}
|
|
126
174
|
|
|
127
175
|
emits {
|
|
@@ -133,9 +181,23 @@ orbital RelatedItemOrbital {
|
|
|
133
181
|
@description "Indicates failure to load related items."
|
|
134
182
|
@synonyms "error, failure, problem, unsuccessful"
|
|
135
183
|
@tier "internal"
|
|
184
|
+
SELECT_RELATED -> external {
|
|
185
|
+
id : string!
|
|
186
|
+
name : string
|
|
187
|
+
}
|
|
188
|
+
@description "Signals a related item was selected to drive a detail view."
|
|
189
|
+
@synonyms "select, choose, open, view"
|
|
190
|
+
@tier "domain"
|
|
136
191
|
}
|
|
137
192
|
|
|
138
193
|
listens {
|
|
194
|
+
SELECT_RELATED {
|
|
195
|
+
id : string!
|
|
196
|
+
name : string
|
|
197
|
+
}
|
|
198
|
+
@description "A related item was selected; the atom records it as the active row."
|
|
199
|
+
@synonyms "select, choose, open, view"
|
|
200
|
+
@tier "domain"
|
|
139
201
|
RelatedItemLoadFailed {
|
|
140
202
|
error : string
|
|
141
203
|
code : string
|
|
@@ -143,9 +205,23 @@ orbital RelatedItemOrbital {
|
|
|
143
205
|
@description "Indicates failure to load related items."
|
|
144
206
|
@synonyms "error, failure, problem, unsuccessful"
|
|
145
207
|
@tier "internal"
|
|
208
|
+
SHOW_RELATED {
|
|
209
|
+
key : string!
|
|
210
|
+
}
|
|
211
|
+
@description "Scopes the related fetch to rows whose relationField equals key."
|
|
212
|
+
@synonyms "scope, filter, focus, target"
|
|
213
|
+
@tier "domain"
|
|
146
214
|
}
|
|
147
215
|
|
|
148
216
|
config {
|
|
217
|
+
title : string = Related
|
|
218
|
+
@label "Section title"
|
|
219
|
+
@description "Heading shown above the related list."
|
|
220
|
+
@tier "presentation"
|
|
221
|
+
relationField : string = ""
|
|
222
|
+
@label "Relation field"
|
|
223
|
+
@description "RelatedItem field compared against SHOW_RELATED's key to scope the fetch to one parent document; empty renders the full unfiltered collection (default)."
|
|
224
|
+
@tier "domain"
|
|
149
225
|
tableLook : "dense" | "spacious" | "striped" | "borderless" | "card-rows" = dense
|
|
150
226
|
@label "Table look"
|
|
151
227
|
@description "Layer 2 visual treatment for the data table rendered by this atom."
|
|
@@ -153,6 +229,7 @@ orbital RelatedItemOrbital {
|
|
|
153
229
|
}
|
|
154
230
|
}
|
|
155
231
|
|
|
156
|
-
;; consumer: parent molecule (e.g. std-related-master-detail) listens for SELECT_RELATED to drive a detail panel
|
|
232
|
+
;; consumer: parent molecule (e.g. std-related-master-detail) listens for SELECT_RELATED to drive a detail panel; a
|
|
233
|
+
;; per-document scope forwards its "opened" event to SHOW_RELATED { key } via a listens override on relationField
|
|
157
234
|
page "/related" as Related -> RelatedItemList
|
|
158
235
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
app std-rich-editor "1.0.0"
|
|
2
|
-
"std-rich-editor — wiki/CMS Notion-style block editor. Browses documents in `browsing`; opens the rich-block-editor on a selected row; persists block edits + publish status."
|
|
2
|
+
"std-rich-editor — wiki/CMS Notion-style block editor. Browses documents in `browsing`; opens the rich-block-editor on a selected row; persists block edits + publish status. `BlockEdit` is a rebindable single-row overlay editor: an organism rebinds it to its own entity (WikiPage, Note, …), passes the row's id + blocksJson via OPEN, and routes the emitted BLOCKS_SAVED into its own persistor — this atom never fetches or persists."
|
|
3
3
|
;; @capabilities "notes app, note-taking, journal, personal journal entries, document editor, write and organize notes"
|
|
4
4
|
type BlockSpec = { type : string!, content : string, id : string }
|
|
5
5
|
type ObjectSpec = { id : string, label : string, value : string }
|
|
@@ -419,5 +419,119 @@ orbital DocumentOrbital {
|
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
trait BlockEdit -> @rebindable Document [interaction, instance] {
|
|
423
|
+
initial: idle
|
|
424
|
+
|
|
425
|
+
state idle {
|
|
426
|
+
INIT -> idle
|
|
427
|
+
OPEN -> editing
|
|
428
|
+
(set @entity.id ?id)
|
|
429
|
+
(set @entity.blocksJson ?blocksJson)
|
|
430
|
+
(render-ui modal {
|
|
431
|
+
children: [{
|
|
432
|
+
align: center
|
|
433
|
+
children: [{ name: file-text, type: icon }, {
|
|
434
|
+
content: @config.title
|
|
435
|
+
type: typography
|
|
436
|
+
variant: h3
|
|
437
|
+
}]
|
|
438
|
+
direction: horizontal
|
|
439
|
+
gap: sm
|
|
440
|
+
type: stack
|
|
441
|
+
}, { type: divider }, {
|
|
442
|
+
changeEvent: BLOCKS_CHANGE
|
|
443
|
+
initialBlocks: @entity.blocksJson
|
|
444
|
+
placeholder: @config.placeholder
|
|
445
|
+
showToolbar: true
|
|
446
|
+
type: rich-block-editor
|
|
447
|
+
}, {
|
|
448
|
+
align: center
|
|
449
|
+
children: [{
|
|
450
|
+
action: SAVE
|
|
451
|
+
label: Save
|
|
452
|
+
type: button
|
|
453
|
+
variant: primary
|
|
454
|
+
}, {
|
|
455
|
+
action: CLOSE
|
|
456
|
+
label: Cancel
|
|
457
|
+
type: button
|
|
458
|
+
variant: ghost
|
|
459
|
+
}]
|
|
460
|
+
direction: horizontal
|
|
461
|
+
gap: sm
|
|
462
|
+
type: stack
|
|
463
|
+
}]
|
|
464
|
+
direction: vertical
|
|
465
|
+
gap: md
|
|
466
|
+
type: stack
|
|
467
|
+
})
|
|
468
|
+
;; self-loop on the external emit so the validator sees an in-atom
|
|
469
|
+
;; listener — the real consumer is the composing organism's persistor.
|
|
470
|
+
BLOCKS_SAVED -> idle
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
state editing {
|
|
474
|
+
BLOCKS_CHANGE -> editing
|
|
475
|
+
(set @entity.blocksJson ?blocks)
|
|
476
|
+
SAVE -> idle
|
|
477
|
+
(render-ui modal null)
|
|
478
|
+
(emit BLOCKS_SAVED { id: @entity.id, blocksJson: @entity.blocksJson })
|
|
479
|
+
CLOSE -> idle
|
|
480
|
+
(render-ui modal null)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
emits {
|
|
484
|
+
BLOCKS_SAVED -> external {
|
|
485
|
+
id : string!
|
|
486
|
+
blocksJson : [BlockSpec]
|
|
487
|
+
}
|
|
488
|
+
@description "Signals a row's block content is ready to persist. This atom never persists — the composing organism routes BLOCKS_SAVED into its own persistor's update event."
|
|
489
|
+
@synonyms "saved, persist, update, commit"
|
|
490
|
+
@tier "domain"
|
|
491
|
+
CLOSE
|
|
492
|
+
@description "Indicates the block editor overlay is being dismissed."
|
|
493
|
+
@synonyms "dismiss, hide, cancel, close"
|
|
494
|
+
@tier "domain"
|
|
495
|
+
BLOCKS_CHANGE {
|
|
496
|
+
blocks : [BlockSpec]
|
|
497
|
+
}
|
|
498
|
+
@description "Signals that the content of a block has been modified while editing."
|
|
499
|
+
@synonyms "update, modify, changed, edit"
|
|
500
|
+
@tier "domain"
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
listens {
|
|
504
|
+
OPEN {
|
|
505
|
+
id : string!
|
|
506
|
+
blocksJson : [BlockSpec]
|
|
507
|
+
}
|
|
508
|
+
@description "Requests the block editor overlay open for the given row. The caller supplies the row's id and current blocks — this trait never fetches them itself."
|
|
509
|
+
@synonyms "show, launch, reveal, edit"
|
|
510
|
+
@tier "domain"
|
|
511
|
+
BLOCKS_CHANGE {
|
|
512
|
+
blocks : [BlockSpec]
|
|
513
|
+
}
|
|
514
|
+
@description "Indicates changes to the content of editable blocks while editing."
|
|
515
|
+
@synonyms "update, modify, edit"
|
|
516
|
+
@tier "domain"
|
|
517
|
+
CLOSE
|
|
518
|
+
@description "Indicates the block editor overlay is being dismissed."
|
|
519
|
+
@synonyms "dismiss, hide, cancel, close"
|
|
520
|
+
@tier "domain"
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
config {
|
|
524
|
+
title : string = "Edit content"
|
|
525
|
+
@label "Editor heading"
|
|
526
|
+
@description "Heading shown at the top of the block editor overlay."
|
|
527
|
+
@tier "presentation"
|
|
528
|
+
placeholder : string = "Start writing…"
|
|
529
|
+
@label "Placeholder text"
|
|
530
|
+
@description "Placeholder shown in the block editor when it is empty."
|
|
531
|
+
@tier "presentation"
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
422
535
|
page "/documents/edit" as DocumentEditPage -> DocumentEdit
|
|
536
|
+
page "/documents/block-edit" as BlockEditPage -> BlockEdit
|
|
423
537
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
app std-tag-taxonomy "1.1.0"
|
|
2
|
-
"std-tag-taxonomy — hierarchical category tag tree (parent/child). TagBrowse fetches Tag rows on INIT
|
|
2
|
+
"std-tag-taxonomy — hierarchical category tag tree (parent/child). TagBrowse fetches root-level Tag rows (parentId = \"\") on INIT and renders the active level via data-grid; SELECT_TAG drills into the chosen tag's children by fetching rows whose parentId matches it, binding @entity.id to that parent so the level is remembered; SHOW_ROOT resets back to the root level, surfaced as a back affordance while drilled in. Flat taxonomies (all parentId \"\") render exactly one level, unchanged. TagSelected is emitted on selection for consumers to filter content by tag."
|
|
3
3
|
orbital TagTaxonomyOrbital {
|
|
4
4
|
type TagLoaded = Event { data : [Tag] } "Fired when the tag collection finishes loading"
|
|
5
5
|
|
|
@@ -10,7 +10,7 @@ orbital TagTaxonomyOrbital {
|
|
|
10
10
|
entity Tag [persistent: tags] {
|
|
11
11
|
id : string!
|
|
12
12
|
name : string! @description "The descriptive label for this item." @synonyms "label, title, description"
|
|
13
|
-
parentId :
|
|
13
|
+
parentId : Tag @description "Reference to the parent tag in the hierarchy; empty marks a root." @synonyms "parent, superior, ancestor"
|
|
14
14
|
slug : string @description "A unique, URL-friendly identifier." @synonyms "identifier, key, code"
|
|
15
15
|
color : string @description "A visual identifier, often used for categorization." @synonyms "hue, shade, tint, category color"
|
|
16
16
|
count : number @description "The number of items associated with this entry." @synonyms "quantity, total, size, amount" = 0
|
|
@@ -22,7 +22,10 @@ orbital TagTaxonomyOrbital {
|
|
|
22
22
|
|
|
23
23
|
state loading {
|
|
24
24
|
INIT -> loading
|
|
25
|
+
(set @entity.id "")
|
|
26
|
+
(set @entity.parentId "")
|
|
25
27
|
(fetch Tag {
|
|
28
|
+
filter: ["=", (object/get @entity parentId), ""]
|
|
26
29
|
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
27
30
|
})
|
|
28
31
|
(render-ui main {
|
|
@@ -41,6 +44,14 @@ orbital TagTaxonomyOrbital {
|
|
|
41
44
|
TagLoaded -> browsing
|
|
42
45
|
(render-ui main {
|
|
43
46
|
children: [{
|
|
47
|
+
action: SHOW_ROOT
|
|
48
|
+
disabled: (if (!= @entity.id "") false true)
|
|
49
|
+
icon: arrow-left
|
|
50
|
+
label: "All categories"
|
|
51
|
+
size: sm
|
|
52
|
+
type: button
|
|
53
|
+
variant: ghost
|
|
54
|
+
}, {
|
|
44
55
|
content: @config.title
|
|
45
56
|
type: typography
|
|
46
57
|
variant: h3
|
|
@@ -115,7 +126,10 @@ orbital TagTaxonomyOrbital {
|
|
|
115
126
|
|
|
116
127
|
state browsing {
|
|
117
128
|
INIT -> loading
|
|
129
|
+
(set @entity.id "")
|
|
130
|
+
(set @entity.parentId "")
|
|
118
131
|
(fetch Tag {
|
|
132
|
+
filter: ["=", (object/get @entity parentId), ""]
|
|
119
133
|
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
120
134
|
})
|
|
121
135
|
(render-ui main {
|
|
@@ -133,8 +147,10 @@ orbital TagTaxonomyOrbital {
|
|
|
133
147
|
})
|
|
134
148
|
SELECT_TAG -> editing
|
|
135
149
|
(set @entity.id ?tagId)
|
|
150
|
+
(set @entity.parentId ?tagId)
|
|
136
151
|
(emit TagSelected { tagId: ?tagId })
|
|
137
152
|
(fetch Tag {
|
|
153
|
+
filter: ["=", (object/get @entity parentId), ?tagId]
|
|
138
154
|
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
139
155
|
})
|
|
140
156
|
(render-ui main {
|
|
@@ -150,9 +166,37 @@ orbital TagTaxonomyOrbital {
|
|
|
150
166
|
gap: md
|
|
151
167
|
type: stack
|
|
152
168
|
})
|
|
169
|
+
SHOW_ROOT -> loading
|
|
170
|
+
(set @entity.id "")
|
|
171
|
+
(set @entity.parentId "")
|
|
172
|
+
(fetch Tag {
|
|
173
|
+
filter: ["=", (object/get @entity parentId), ""]
|
|
174
|
+
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
175
|
+
})
|
|
176
|
+
(render-ui main {
|
|
177
|
+
align: center
|
|
178
|
+
children: [{ type: spinner }, {
|
|
179
|
+
color: muted
|
|
180
|
+
content: "Loading categories…"
|
|
181
|
+
type: typography
|
|
182
|
+
variant: caption
|
|
183
|
+
}]
|
|
184
|
+
className: py-12
|
|
185
|
+
direction: vertical
|
|
186
|
+
gap: md
|
|
187
|
+
type: stack
|
|
188
|
+
})
|
|
153
189
|
TagLoaded -> browsing
|
|
154
190
|
(render-ui main {
|
|
155
191
|
children: [{
|
|
192
|
+
action: SHOW_ROOT
|
|
193
|
+
disabled: (if (!= @entity.id "") false true)
|
|
194
|
+
icon: arrow-left
|
|
195
|
+
label: "All categories"
|
|
196
|
+
size: sm
|
|
197
|
+
type: button
|
|
198
|
+
variant: ghost
|
|
199
|
+
}, {
|
|
156
200
|
content: @config.title
|
|
157
201
|
type: typography
|
|
158
202
|
variant: h3
|
|
@@ -227,7 +271,10 @@ orbital TagTaxonomyOrbital {
|
|
|
227
271
|
|
|
228
272
|
state editing {
|
|
229
273
|
INIT -> loading
|
|
274
|
+
(set @entity.id "")
|
|
275
|
+
(set @entity.parentId "")
|
|
230
276
|
(fetch Tag {
|
|
277
|
+
filter: ["=", (object/get @entity parentId), ""]
|
|
231
278
|
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
232
279
|
})
|
|
233
280
|
(render-ui main {
|
|
@@ -245,12 +292,22 @@ orbital TagTaxonomyOrbital {
|
|
|
245
292
|
})
|
|
246
293
|
SELECT_TAG -> editing
|
|
247
294
|
(set @entity.id ?tagId)
|
|
295
|
+
(set @entity.parentId ?tagId)
|
|
248
296
|
(emit TagSelected { tagId: ?tagId })
|
|
249
297
|
TagSelected -> editing
|
|
250
298
|
(set @entity.id ?tagId)
|
|
299
|
+
(set @entity.parentId ?tagId)
|
|
251
300
|
TagLoaded -> browsing
|
|
252
301
|
(render-ui main {
|
|
253
302
|
children: [{
|
|
303
|
+
action: SHOW_ROOT
|
|
304
|
+
disabled: (if (!= @entity.id "") false true)
|
|
305
|
+
icon: arrow-left
|
|
306
|
+
label: "All categories"
|
|
307
|
+
size: sm
|
|
308
|
+
type: button
|
|
309
|
+
variant: ghost
|
|
310
|
+
}, {
|
|
254
311
|
content: @config.title
|
|
255
312
|
type: typography
|
|
256
313
|
variant: h3
|
|
@@ -325,7 +382,10 @@ orbital TagTaxonomyOrbital {
|
|
|
325
382
|
|
|
326
383
|
state error {
|
|
327
384
|
INIT -> loading
|
|
385
|
+
(set @entity.id "")
|
|
386
|
+
(set @entity.parentId "")
|
|
328
387
|
(fetch Tag {
|
|
388
|
+
filter: ["=", (object/get @entity parentId), ""]
|
|
329
389
|
emit: { failure: TagLoadFailed, success: TagLoaded }
|
|
330
390
|
})
|
|
331
391
|
(render-ui main {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
app std-thread "1.3.0"
|
|
2
|
-
"std-thread — forum-style nested replies with collapse + flat-mode toggle. Owns ThreadPost (persistent). flat:true covers 1:1 linear inquiry threads; flat:false renders forum-style nested. INIT fetches, scoped by @config.threadRootId when set (blank = every root, the default). REPLY persists a child post under @payload.parentId, stamped with the real @user identity. Layer 3 variants override `bodyContent` to deliver chat-bubble, email-threaded, or linear-comments UX while inheriting the same trait, state machine, emits, and listens."
|
|
2
|
+
"std-thread — forum-style nested replies with collapse + flat-mode toggle. Owns ThreadPost (persistent). flat:true covers 1:1 linear inquiry threads; flat:false renders forum-style nested. INIT fetches, scoped by @config.threadRootId when set (blank = every root, the default). REPLY persists a child post under @payload.parentId, stamped with the real @user identity. A consumer that mounts this as page comments forwards its own document-opened signal to SET_THREAD_ROOT { rootId }, which stamps the frame and refetches filtered by the payload; the after-create and after-select refetch arms keep filtering by @config.threadRootId, so a mutation re-widens the panel until the consumer re-fires SET_THREAD_ROOT. Layer 3 variants override `bodyContent` to deliver chat-bubble, email-threaded, or linear-comments UX while inheriting the same trait, state machine, emits, and listens."
|
|
3
3
|
orbital ThreadPostOrbital {
|
|
4
4
|
;; Forward relation: array of child ThreadPost IDs whose parentId === this.id.
|
|
5
5
|
;; Lowers to `type: "relation", cardinality: "many"` (orbital-lolo lower.rs).
|
|
@@ -19,6 +19,8 @@ orbital ThreadPostOrbital {
|
|
|
19
19
|
|
|
20
20
|
type ThreadPostCreateFailed = Event { error : string, code : string } "Fired when a new thread-post fails to persist"
|
|
21
21
|
|
|
22
|
+
type SetThreadRoot = Event { rootId : string! } "Fired to scope every ThreadPost fetch, and new-reply threadRootId stamping, to the descendants of one document root"
|
|
23
|
+
|
|
22
24
|
entity ThreadPost [persistent: threadposts] {
|
|
23
25
|
id : string!
|
|
24
26
|
parentId : string @description "Identifier of the parent ThreadPost in a nested thread." @synonyms "parent, ancestor, source"
|
|
@@ -52,6 +54,14 @@ orbital ThreadPostOrbital {
|
|
|
52
54
|
type: alert
|
|
53
55
|
variant: error
|
|
54
56
|
})
|
|
57
|
+
SET_THREAD_ROOT -> loading
|
|
58
|
+
(set @entity.threadRootId ?rootId)
|
|
59
|
+
(fetch ThreadPost {
|
|
60
|
+
emit: { failure: ThreadPostLoadFailed, success: ThreadPostLoaded }
|
|
61
|
+
filter: (or ["=", ?rootId, ""] ["=", (object/get @entity threadRootId), ?rootId])
|
|
62
|
+
include: (replies)
|
|
63
|
+
})
|
|
64
|
+
(render-ui main { size: sm, type: spinner })
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
state browsing {
|
|
@@ -73,13 +83,14 @@ orbital ThreadPostOrbital {
|
|
|
73
83
|
authorName: @user.name
|
|
74
84
|
content: ?content
|
|
75
85
|
parentId: (str/default ?parentNodeId ?parentId)
|
|
76
|
-
threadRootId: (str/default ?parentNodeId (str/default @config.threadRootId root))
|
|
86
|
+
threadRootId: (str/default ?parentNodeId (str/default @entity.threadRootId (str/default @config.threadRootId root)))
|
|
77
87
|
} {
|
|
78
88
|
emit: { failure: ThreadPostCreateFailed, success: ThreadPostCreated }
|
|
79
89
|
})
|
|
80
90
|
;; Reply with no text yet (e.g. an email "Reply" button) opens the composer.
|
|
81
91
|
REPLY -> replying when ["=", (str/default ?content ""), ""]
|
|
82
92
|
(set @entity.parentId (str/default ?parentNodeId ?parentId))
|
|
93
|
+
(set @entity.threadRootId (str/default ?parentNodeId (str/default @entity.threadRootId (str/default @config.threadRootId root))))
|
|
83
94
|
(render-ui main {
|
|
84
95
|
children: [{
|
|
85
96
|
content: "Write a reply"
|
|
@@ -139,6 +150,14 @@ orbital ThreadPostOrbital {
|
|
|
139
150
|
type: alert
|
|
140
151
|
variant: error
|
|
141
152
|
})
|
|
153
|
+
SET_THREAD_ROOT -> loading
|
|
154
|
+
(set @entity.threadRootId ?rootId)
|
|
155
|
+
(fetch ThreadPost {
|
|
156
|
+
emit: { failure: ThreadPostLoadFailed, success: ThreadPostLoaded }
|
|
157
|
+
filter: (or ["=", ?rootId, ""] ["=", (object/get @entity threadRootId), ?rootId])
|
|
158
|
+
include: (replies)
|
|
159
|
+
})
|
|
160
|
+
(render-ui main { size: sm, type: spinner })
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
state replying {
|
|
@@ -165,6 +184,14 @@ orbital ThreadPostOrbital {
|
|
|
165
184
|
type: alert
|
|
166
185
|
variant: error
|
|
167
186
|
})
|
|
187
|
+
SET_THREAD_ROOT -> loading
|
|
188
|
+
(set @entity.threadRootId ?rootId)
|
|
189
|
+
(fetch ThreadPost {
|
|
190
|
+
emit: { failure: ThreadPostLoadFailed, success: ThreadPostLoaded }
|
|
191
|
+
filter: (or ["=", ?rootId, ""] ["=", (object/get @entity threadRootId), ?rootId])
|
|
192
|
+
include: (replies)
|
|
193
|
+
})
|
|
194
|
+
(render-ui main { size: sm, type: spinner })
|
|
168
195
|
}
|
|
169
196
|
|
|
170
197
|
state error {
|
|
@@ -175,6 +202,14 @@ orbital ThreadPostOrbital {
|
|
|
175
202
|
include: (replies)
|
|
176
203
|
})
|
|
177
204
|
(render-ui main { size: sm, type: spinner })
|
|
205
|
+
SET_THREAD_ROOT -> loading
|
|
206
|
+
(set @entity.threadRootId ?rootId)
|
|
207
|
+
(fetch ThreadPost {
|
|
208
|
+
emit: { failure: ThreadPostLoadFailed, success: ThreadPostLoaded }
|
|
209
|
+
filter: (or ["=", ?rootId, ""] ["=", (object/get @entity threadRootId), ?rootId])
|
|
210
|
+
include: (replies)
|
|
211
|
+
})
|
|
212
|
+
(render-ui main { size: sm, type: spinner })
|
|
178
213
|
}
|
|
179
214
|
|
|
180
215
|
emits {
|
|
@@ -295,6 +330,12 @@ orbital ThreadPostOrbital {
|
|
|
295
330
|
@description "Indicates a failure to create a new thread post."
|
|
296
331
|
@synonyms "error, failure, rejected, invalid"
|
|
297
332
|
@tier "internal"
|
|
333
|
+
SET_THREAD_ROOT {
|
|
334
|
+
rootId : string!
|
|
335
|
+
}
|
|
336
|
+
@description "Scopes every fetch, and new-reply threadRootId stamping, to the descendants of one document root."
|
|
337
|
+
@synonyms "scope, focus, set root, document scope, thread scope"
|
|
338
|
+
@tier "domain"
|
|
298
339
|
}
|
|
299
340
|
|
|
300
341
|
config {
|