@alstar/studio 0.0.0-beta.15 → 0.0.0-beta.16
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/components/BlockFieldRenderer.ts +1 -1
- package/components/FieldRenderer.ts +7 -2
- package/components/Render.ts +6 -1
- package/components/fields/Reference.ts +67 -0
- package/components/fields/index.ts +2 -1
- package/package.json +3 -3
- package/public/studio/main.css +1 -0
- package/queries/block-2.ts +15 -15
- package/schemas.ts +1 -1
- package/types.ts +16 -10
- package/utils/get-or-create-row.ts +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Field } from './fields/index.ts'
|
|
2
2
|
import type { BlocksFieldDefStructure, FieldDefStructure } from '../types.ts'
|
|
3
3
|
import BlockFieldRenderer from './BlockFieldRenderer.ts'
|
|
4
|
+
import { BlockFieldInstance } from '../utils/define.ts'
|
|
4
5
|
|
|
5
6
|
export default (props: {
|
|
6
7
|
entryId: number
|
|
@@ -11,6 +12,10 @@ export default (props: {
|
|
|
11
12
|
}) => {
|
|
12
13
|
const { entryId, parentId, structure, name, id } = props
|
|
13
14
|
|
|
15
|
+
if (structure.instanceOf === BlockFieldInstance) {
|
|
16
|
+
return BlockFieldRenderer({ entryId, parentId, name, structure, id })
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
switch (structure.type) {
|
|
15
20
|
case 'text': {
|
|
16
21
|
return Field.Text({ entryId, parentId, name, id, structure })
|
|
@@ -28,8 +33,8 @@ export default (props: {
|
|
|
28
33
|
return Field.Text({ entryId, parentId, name, structure, id })
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
case '
|
|
32
|
-
return
|
|
36
|
+
case 'reference': {
|
|
37
|
+
return Field.Reference({ entryId, parentId, name, structure, id })
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
40
|
}
|
package/components/Render.ts
CHANGED
|
@@ -41,6 +41,11 @@ export default (props: {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
} catch (error) {
|
|
44
|
-
|
|
44
|
+
console.log(error)
|
|
45
|
+
|
|
46
|
+
return html`
|
|
47
|
+
<p>Error rendering "${name}"</p>
|
|
48
|
+
<pre><code>${JSON.stringify(error, null, 2)}</code></pre>
|
|
49
|
+
`
|
|
45
50
|
}
|
|
46
51
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getOrCreateRow } from '../../utils/get-or-create-row.ts'
|
|
2
|
+
import { html } from '../../utils/html.ts'
|
|
3
|
+
import type { FieldDefStructure, ReferenceFieldStructure } from '../../types.ts'
|
|
4
|
+
import { query } from '../../queries/index.ts'
|
|
5
|
+
|
|
6
|
+
export default (props: {
|
|
7
|
+
entryId: number
|
|
8
|
+
parentId: number
|
|
9
|
+
name: string
|
|
10
|
+
id?: number
|
|
11
|
+
structure: ReferenceFieldStructure
|
|
12
|
+
sortOrder?: number
|
|
13
|
+
}) => {
|
|
14
|
+
const { entryId, parentId, name, structure, sortOrder = 0, id } = props
|
|
15
|
+
|
|
16
|
+
const data = getOrCreateRow({
|
|
17
|
+
parentId,
|
|
18
|
+
name,
|
|
19
|
+
field: structure,
|
|
20
|
+
sortOrder,
|
|
21
|
+
id,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (!data) return html`<p>No block</p>`
|
|
25
|
+
|
|
26
|
+
const entries = query.roots({ type: structure.to }, { depth: 1 })
|
|
27
|
+
|
|
28
|
+
return html`
|
|
29
|
+
<form
|
|
30
|
+
data-on-input="@patch('/studio/api/block', {
|
|
31
|
+
contentType: 'form',
|
|
32
|
+
headers: {
|
|
33
|
+
render: ''
|
|
34
|
+
}
|
|
35
|
+
})"
|
|
36
|
+
>
|
|
37
|
+
<hgroup>
|
|
38
|
+
<label for="block-${data.id}">${structure.label}</label>
|
|
39
|
+
${structure.description &&
|
|
40
|
+
html`
|
|
41
|
+
<p><small>${structure.description}</small></p>
|
|
42
|
+
`}
|
|
43
|
+
</hgroup>
|
|
44
|
+
|
|
45
|
+
<input
|
|
46
|
+
list="entries-${data.id}"
|
|
47
|
+
id="block-${data.id}"
|
|
48
|
+
name="value"
|
|
49
|
+
value="${data.value}"
|
|
50
|
+
/>
|
|
51
|
+
<datalist id="entries-${data.id}">
|
|
52
|
+
${entries.map((entry) => {
|
|
53
|
+
return html`<option value="${entry.fields.slug.value}">
|
|
54
|
+
${entry.fields.title.value}
|
|
55
|
+
</option>`
|
|
56
|
+
})}
|
|
57
|
+
</datalist>
|
|
58
|
+
|
|
59
|
+
<input type="hidden" name="id" value="${data.id}" />
|
|
60
|
+
|
|
61
|
+
<!-- <input type="hidden" name="type" value="{structure.type}" />
|
|
62
|
+
<input type="hidden" name="entryId" value="{entryId}" />
|
|
63
|
+
<input type="hidden" name="parentId" value="{parentId}" />
|
|
64
|
+
<input type="hidden" name="name" value="{name}" /> -->
|
|
65
|
+
</form>
|
|
66
|
+
`
|
|
67
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Text from './Text.ts'
|
|
2
2
|
import Markdown from './Markdown.ts'
|
|
3
3
|
import Slug, { routes as slugRoutes } from './Slug.ts'
|
|
4
|
+
import Reference from './Reference.ts'
|
|
4
5
|
|
|
5
|
-
export const Field = { Text, Markdown, Slug }
|
|
6
|
+
export const Field = { Text, Markdown, Slug, Reference }
|
|
6
7
|
|
|
7
8
|
export const fieldRoutes = [slugRoutes]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alstar/studio",
|
|
3
|
-
"version": "0.0.0-beta.
|
|
3
|
+
"version": "0.0.0-beta.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
"@hono/node-server": "^1.18.1",
|
|
14
14
|
"@starfederation/datastar-sdk": "1.0.0-RC.1",
|
|
15
15
|
"hono": "^4.8.12",
|
|
16
|
-
"@alstar/
|
|
16
|
+
"@alstar/db": "0.0.0-beta.1",
|
|
17
17
|
"@alstar/refresher": "0.0.0-beta.3",
|
|
18
|
-
"@alstar/
|
|
18
|
+
"@alstar/ui": "0.0.0-beta.3"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^24.1.0",
|
package/public/studio/main.css
CHANGED
package/queries/block-2.ts
CHANGED
|
@@ -7,7 +7,7 @@ function buildForest(blocks: DBBlockResult[]): DBBlockResult[] {
|
|
|
7
7
|
const roots: DBBlockResult[] = []
|
|
8
8
|
|
|
9
9
|
for (const block of blocks) {
|
|
10
|
-
block.
|
|
10
|
+
block.blocks = []
|
|
11
11
|
map.set(block.id, block)
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -16,14 +16,14 @@ function buildForest(blocks: DBBlockResult[]): DBBlockResult[] {
|
|
|
16
16
|
roots.push(block)
|
|
17
17
|
} else {
|
|
18
18
|
const parent = map.get(block.parent_id)
|
|
19
|
-
if (parent) parent.
|
|
19
|
+
if (parent) parent.blocks!.push(block)
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Sort
|
|
23
|
+
// Sort blocks by sort_order recursively
|
|
24
24
|
const sortChildren = (node: DBBlockResult) => {
|
|
25
|
-
node.
|
|
26
|
-
node.
|
|
25
|
+
node.blocks!.sort((a, b) => a.sort_order - b.sort_order)
|
|
26
|
+
node.blocks!.forEach(sortChildren)
|
|
27
27
|
}
|
|
28
28
|
roots.forEach(sortChildren)
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@ function buildTree(blocks: DBBlockResult[]): DBBlockResult {
|
|
|
35
35
|
const roots: DBBlockResult[] = []
|
|
36
36
|
|
|
37
37
|
for (const block of blocks) {
|
|
38
|
-
block.
|
|
38
|
+
block.blocks = []
|
|
39
39
|
map.set(block.id, block)
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -44,14 +44,14 @@ function buildTree(blocks: DBBlockResult[]): DBBlockResult {
|
|
|
44
44
|
roots.push(block)
|
|
45
45
|
} else {
|
|
46
46
|
const parent = map.get(block.parent_id)
|
|
47
|
-
if (parent) parent.
|
|
47
|
+
if (parent) parent.blocks!.push(block)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
// Sort
|
|
51
|
+
// Sort blocks by sort_order recursively
|
|
52
52
|
const sortChildren = (node: DBBlockResult) => {
|
|
53
|
-
node.
|
|
54
|
-
node.
|
|
53
|
+
node.blocks!.sort((a, b) => a.sort_order - b.sort_order)
|
|
54
|
+
node.blocks!.forEach(sortChildren)
|
|
55
55
|
}
|
|
56
56
|
roots.forEach(sortChildren)
|
|
57
57
|
|
|
@@ -65,7 +65,7 @@ function transformBlocksTree(
|
|
|
65
65
|
const fields: Record<string, DBBlockResult> = {}
|
|
66
66
|
let hasFields = false
|
|
67
67
|
|
|
68
|
-
for (const child of block.
|
|
68
|
+
for (const child of block.blocks ?? []) {
|
|
69
69
|
const transformedChild = transformBlocksTree(
|
|
70
70
|
child,
|
|
71
71
|
child.type === 'blocks',
|
|
@@ -82,7 +82,7 @@ function transformBlocksTree(
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
if (!isBlocksChild) {
|
|
85
|
-
delete block.
|
|
85
|
+
delete block.blocks
|
|
86
86
|
} else {
|
|
87
87
|
delete block.fields
|
|
88
88
|
}
|
|
@@ -265,7 +265,7 @@ function buildTree2(items: DBRow[]): TODO | null {
|
|
|
265
265
|
|
|
266
266
|
let root: TODO | null = null;
|
|
267
267
|
|
|
268
|
-
// Second pass: assign
|
|
268
|
+
// Second pass: assign blocks to parents
|
|
269
269
|
for (const item of map.values()) {
|
|
270
270
|
if (item.parent_id === null) {
|
|
271
271
|
root = item; // Root node
|
|
@@ -273,8 +273,8 @@ function buildTree2(items: DBRow[]): TODO | null {
|
|
|
273
273
|
const parent = map.get(item.parent_id);
|
|
274
274
|
if (parent) {
|
|
275
275
|
if(parent.type === 'blocks') {
|
|
276
|
-
if (!parent.
|
|
277
|
-
parent.
|
|
276
|
+
if (!parent.blocks) parent.blocks = [];
|
|
277
|
+
parent.blocks.push(item);
|
|
278
278
|
} else {
|
|
279
279
|
if (!parent.fields) parent.fields = {};
|
|
280
280
|
parent.fields[item.name] = item;
|
package/schemas.ts
CHANGED
package/types.ts
CHANGED
|
@@ -21,14 +21,13 @@ export type DeepReadonly<T> =
|
|
|
21
21
|
export type PrimitiveField = {
|
|
22
22
|
name: string
|
|
23
23
|
label: string
|
|
24
|
-
type: 'text' | 'slug' | 'markdown' | 'image'
|
|
24
|
+
type: 'text' | 'slug' | 'markdown' | 'image' | 'reference'
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export type BlockField = {
|
|
28
28
|
name: string
|
|
29
29
|
label: string
|
|
30
|
-
|
|
31
|
-
children: Record<string, Field | Block>
|
|
30
|
+
blocks: Record<string, Field | Block>
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
export type Field = PrimitiveField | BlockField
|
|
@@ -44,7 +43,7 @@ export type Structure = Record<string, BlockDefStructure>
|
|
|
44
43
|
// export type Structure = Record<string, BlockDefStructure>
|
|
45
44
|
|
|
46
45
|
// --- Field & block definitions ---
|
|
47
|
-
type FieldType = 'text' | 'slug' | 'markdown' | 'image'
|
|
46
|
+
type FieldType = 'text' | 'slug' | 'markdown' | 'image' | 'reference'
|
|
48
47
|
|
|
49
48
|
interface BaseField {
|
|
50
49
|
label: string
|
|
@@ -68,19 +67,27 @@ interface ImageFieldStructure extends ImageField {
|
|
|
68
67
|
instanceOf: typeof FieldInstance
|
|
69
68
|
}
|
|
70
69
|
|
|
70
|
+
interface ReferenceField extends BaseField {
|
|
71
|
+
type: 'reference'
|
|
72
|
+
to: string | string[]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ReferenceFieldStructure extends ReferenceField {
|
|
76
|
+
instanceOf: typeof FieldInstance
|
|
77
|
+
}
|
|
78
|
+
|
|
71
79
|
export interface BlocksFieldDef {
|
|
72
80
|
label: string
|
|
73
|
-
type: 'blocks'
|
|
74
81
|
description?: string
|
|
75
|
-
|
|
82
|
+
blocks: Record<string, BlockDefStructure | FieldDefStructure>
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
export interface BlocksFieldDefStructure extends BlocksFieldDef {
|
|
79
86
|
instanceOf: typeof BlockFieldInstance
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
export type FieldDef = TextField | ImageField
|
|
83
|
-
export type FieldDefStructure = TextFieldStructure | ImageFieldStructure
|
|
89
|
+
export type FieldDef = TextField | ImageField | ReferenceField
|
|
90
|
+
export type FieldDefStructure = TextFieldStructure | ImageFieldStructure | ReferenceFieldStructure
|
|
84
91
|
|
|
85
92
|
export interface BlockDef {
|
|
86
93
|
label: string
|
|
@@ -127,8 +134,7 @@ export type DBPrimitiveFieldResult = BaseDBResult & {
|
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
export type DBBlockFieldResult = BaseDBResult & {
|
|
130
|
-
|
|
131
|
-
children: DBBlockResult[]
|
|
137
|
+
blocks: DBBlockResult[]
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
export type DBBlockResult = BaseDBResult & {
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
BlocksFieldDefStructure,
|
|
6
6
|
FieldDefStructure,
|
|
7
7
|
} from '../types.ts'
|
|
8
|
+
import { BlockFieldInstance } from './define.ts'
|
|
8
9
|
|
|
9
10
|
export function getOrCreateRow(props: {
|
|
10
11
|
parentId: string | number | null
|
|
@@ -32,7 +33,7 @@ export function getOrCreateRow(props: {
|
|
|
32
33
|
const change = db.insertInto('blocks', {
|
|
33
34
|
name: name?.toString(),
|
|
34
35
|
label: field.label?.toString(),
|
|
35
|
-
type: field.type?.toString(),
|
|
36
|
+
type: field.instanceOf === BlockFieldInstance ? 'blocks' : field.type?.toString(),
|
|
36
37
|
sort_order: sortOrder,
|
|
37
38
|
parent_id: parentId,
|
|
38
39
|
})
|