@alstar/studio 0.0.0-beta.4 → 0.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.
Files changed (43) hide show
  1. package/api/api-key.ts +74 -0
  2. package/api/block.ts +39 -21
  3. package/api/index.ts +9 -1
  4. package/api/mcp.ts +53 -0
  5. package/bin/alstar.ts +42 -0
  6. package/components/{AdminPanel/AdminPanel.ts → AdminPanel.ts} +22 -27
  7. package/components/Block.ts +51 -112
  8. package/components/Entries.ts +17 -10
  9. package/components/Entry.ts +9 -15
  10. package/components/Settings.ts +98 -0
  11. package/components/fields/Blocks.ts +118 -0
  12. package/components/fields/Text.ts +42 -0
  13. package/components/fields/index.ts +4 -0
  14. package/components/icons.ts +97 -0
  15. package/components/index.ts +1 -1
  16. package/components/layout.ts +8 -5
  17. package/index.ts +48 -20
  18. package/package.json +2 -1
  19. package/public/admin-panel.css +90 -0
  20. package/public/blocks.css +53 -0
  21. package/public/main.css +11 -1
  22. package/public/main.js +4 -0
  23. package/public/settings.css +24 -0
  24. package/queries/block-with-children.ts +74 -0
  25. package/queries/block.ts +287 -0
  26. package/queries/db-types.ts +15 -0
  27. package/queries/getBlockTrees-2.ts +0 -0
  28. package/queries/getBlockTrees.ts +316 -0
  29. package/queries/getBlocks.ts +214 -0
  30. package/queries/index.ts +2 -98
  31. package/queries/structure-types.ts +97 -0
  32. package/schemas.ts +15 -54
  33. package/types.ts +95 -5
  34. package/utils/buildBlocksTree.ts +4 -4
  35. package/utils/define.ts +21 -5
  36. package/utils/file-based-router.ts +9 -1
  37. package/utils/get-config.ts +8 -9
  38. package/utils/get-or-create-row.ts +28 -0
  39. package/utils/startup-log.ts +9 -0
  40. package/components/AdminPanel/AdminPanel.css +0 -59
  41. package/components/Field.ts +0 -164
  42. package/components/Fields.ts +0 -43
  43. /package/{components/Entry.css → public/entry.css} +0 -0
@@ -0,0 +1,97 @@
1
+ // structure-types.ts
2
+ import { type DBBase } from "./db-types.ts";
3
+
4
+ /**
5
+ * Extract helpers
6
+ */
7
+ type ArrayElement<T> = T extends readonly (infer U)[] ? U : never;
8
+
9
+ /**
10
+ * Field definition shape inferred from defineField(...) (the runtime helper)
11
+ * We keep it generic as "any" shape but with the important properties present
12
+ */
13
+ type FieldDef = {
14
+ readonly name: string;
15
+ readonly type: string;
16
+ readonly fields?: readonly any[]; // only present when type === 'blocks'
17
+ };
18
+
19
+ /**
20
+ * Block definition shape inferred from defineBlock(...) (the runtime helper)
21
+ */
22
+ type BlockDef = {
23
+ readonly name: string;
24
+ readonly type: string;
25
+ readonly fields?: readonly FieldDef[];
26
+ };
27
+
28
+ /**
29
+ * Primitive field node (non-'blocks'): DBBase + kept fields but no children
30
+ */
31
+ type PrimitiveFieldNode<TField extends FieldDef> =
32
+ DBBase & {
33
+ readonly name: TField["name"];
34
+ readonly type: TField["type"];
35
+ // no children (leaf), no nested fields
36
+ readonly children?: [];
37
+ readonly fields?: {}; // empty object for leaf
38
+ };
39
+
40
+ /**
41
+ * For 'blocks' typed field, we need:
42
+ * - the block node representing the 'blocks' wrapper (has DBBase props)
43
+ * - its 'children' are an array of BlockNodes corresponding to nested block defs supplied in the field's 'fields' array
44
+ * - its 'fields' property is the mapping of its own child-field names (can be empty)
45
+ */
46
+ type BlocksFieldNode<
47
+ TField extends FieldDef,
48
+ TFieldDefs extends readonly BlockDef[]
49
+ > = DBBase & {
50
+ readonly name: TField["name"]; // e.g. "blocks" or "images"
51
+ readonly type: "blocks"; // literally 'blocks'
52
+ readonly children: BlockNodeFromBlockDefs<TFieldDefs>[]; // children are instances of the nested blocks
53
+ readonly fields: FieldsFromFieldDefs<TFieldDefs[number]["fields"]>; // the blocks-wrapper's own fields mapping (if any)
54
+ };
55
+
56
+ /**
57
+ * Build the 'fields' object for a set of FieldDef[].
58
+ * Maps each field name -> either PrimitiveFieldNode or BlocksFieldNode recursively.
59
+ */
60
+ type FieldsFromFieldDefs<TDefs> =
61
+ // If no fields
62
+ TDefs extends readonly any[]
63
+ ? {
64
+ // For each field F in TDefs, map F['name'] -> node type
65
+ [F in ArrayElement<TDefs> as F extends { name: infer N extends string } ? N : never]:
66
+ F extends { type: "blocks"; fields: readonly BlockDef[] }
67
+ ? BlocksFieldNode<F, F["fields"]>
68
+ : PrimitiveFieldNode<F>;
69
+ }
70
+ : {};
71
+
72
+ /**
73
+ * A Block node type for a particular BlockDef.
74
+ * - fields: mapping derived from the block's declared fields
75
+ * - children: by default [], because in our final shape all immediate children are placed under 'fields' of the parent.
76
+ * BUT for nodes that are themselves 'blocks' wrappers (i.e. appear as a Block instance of a nested block def),
77
+ * their 'children' will contain actual child blocks (these are handled via BlocksFieldNode above).
78
+ */
79
+ export type BlockNode<T extends BlockDef> = DBBase & {
80
+ readonly name: T["name"];
81
+ readonly type: T["type"];
82
+ readonly fields: FieldsFromFieldDefs<T["fields"]>;
83
+ // for regular block nodes, children will usually be [] (top-level parent's children moved into fields)
84
+ readonly children: [];
85
+ };
86
+
87
+ /**
88
+ * Construct BlockNode unions for a set of block defs (used when blocks field has multiple block subdefs)
89
+ */
90
+ type BlockNodeFromBlockDefs<TDefs extends readonly BlockDef[]> =
91
+ ArrayElement<TDefs> extends infer B ? (B extends BlockDef ? BlockNode<B> : never) : never;
92
+
93
+ /**
94
+ * The top-level forest return type when you pass a structure: it's an array of BlockNode of any top-level BlockDef
95
+ */
96
+ export type BlockTreeFromStructure<TStructure extends readonly BlockDef[]> =
97
+ BlockNodeFromBlockDefs<TStructure>;
package/schemas.ts CHANGED
@@ -1,56 +1,5 @@
1
1
  import { sql } from './utils/sql.ts'
2
2
 
3
- // export const entriesTable = {
4
- // tableName: 'entries',
5
- // columns: sql`
6
- // title TEXT not null, -- Title of the page
7
- // slug TEXT not null unique, -- URL slug for the page
8
- // meta_description TEXT -- Optional meta description for SEO
9
- // `,
10
- // }
11
-
12
- // export const fieldTable = {
13
- // tableName: 'fields',
14
- // columns: sql`
15
- // name TEXT not null, -- Name of the field (e.g., "content", "header", "image")
16
- // type TEXT not null, -- Field type (e.g., "text", "image", "video")
17
- // label TEXT not null, -- Field label (e.g., "Text", "Image", "Video")
18
- // options TEXT -- Additional options or settings (can be a JSON string if needed)
19
- // `,
20
- // }
21
-
22
- // export const entriesFieldsTable = {
23
- // tableName: 'entry_fields',
24
- // columns: sql`
25
- // entry_id INTEGER not null, -- Foreign key to pages
26
- // field_id INTEGER not null, -- Foreign key to fields
27
- // position INTEGER, -- Optional: order of the field on the page
28
- // content TEXT, -- Content of the field (e.g., text, image URL, etc.)
29
- // foreign key (entry_id) references entries (id),
30
- // foreign key (field_id) references fields (id)
31
- // `,
32
- // }
33
-
34
- // export const entryTypeTable = {
35
- // tableName: 'entry_types',
36
- // columns: sql`
37
- // name TEXT not null, -- Name of the field (e.g., "content", "header", "image")
38
- // type TEXT not null, -- Field type (e.g., "text", "image", "video")
39
- // label TEXT not null, -- Field label (e.g., "Text", "Image", "Video")
40
- // options TEXT -- Additional options or settings (can be a JSON string if needed)
41
- // `,
42
- // }
43
-
44
- // export const entryEntryTypeTable = {
45
- // tableName: 'entry_entry_types',
46
- // columns: sql`
47
- // entry_id INTEGER not null, -- Foreign key to pages
48
- // entry_type_id INTEGER not null, -- Foreign key to fields
49
- // foreign key (entry_id) references entries (id),
50
- // foreign key (entry_type_id) references entry_types (id)
51
- // `,
52
- // }
53
-
54
3
  // -- Blocks
55
4
  export const blocksTable = {
56
5
  tableName: 'blocks',
@@ -58,10 +7,22 @@ export const blocksTable = {
58
7
  name TEXT not null,
59
8
  label TEXT not null,
60
9
  type TEXT not null,
61
- sort_order INTEGER not null default 0,
62
10
  value TEXT,
63
11
  options JSON,
64
- parent_block_id INTEGER,
65
- foreign key (parent_block_id) references blocks (id)
12
+ status TEXT default 'enabled',
13
+ sort_order INTEGER not null default 0,
14
+ _depth INTEGER,
15
+ parent_id INTEGER,
16
+ foreign key (parent_id) references blocks (id)
17
+ `,
18
+ }
19
+
20
+ // -- API keys
21
+ export const apiKeysTable = {
22
+ tableName: 'api_keys',
23
+ columns: sql`
24
+ name TEXT not null,
25
+ value TEXT,
26
+ hint TEXT
66
27
  `,
67
28
  }
package/types.ts CHANGED
@@ -1,14 +1,94 @@
1
- import { type HonoOptions } from "hono/hono-base"
2
- import { type BlankEnv } from "hono/types"
1
+ import { type HttpBindings } from '@hono/node-server'
2
+ import { type Context } from 'hono'
3
+ import { type HonoOptions } from 'hono/hono-base'
4
+ import { type BlankInput, type BlankEnv } from 'hono/types'
5
+
6
+ export type PrimitiveField = {
7
+ name: string
8
+ label: string
9
+ type: 'text' | 'slug' | 'markdown' | 'image'
10
+ }
11
+
12
+ export type BlockField = {
13
+ name: string
14
+ label: string
15
+ type: 'blocks'
16
+ children: Record<string, Field | Block>
17
+ }
18
+
19
+ export type Field = PrimitiveField | BlockField
3
20
 
4
21
  export type Block = {
5
22
  name: string
6
23
  label: string
7
24
  type: string
8
- fields?: Block[]
25
+ fields: Record<string, Field | Block>
26
+ }
27
+
28
+ export type Structure = Record<string, BlockDef>
29
+
30
+ // --- Field & block definitions ---
31
+ type FieldType = 'text' | 'slug' | 'markdown' | 'blocks' | 'image';
32
+
33
+ interface BaseField {
34
+ label: string;
35
+ type: FieldType;
36
+ description?: string
37
+ }
38
+
39
+ interface TextField extends BaseField {
40
+ type: 'text' | 'slug' | 'markdown';
9
41
  }
10
42
 
11
- export type Structure = Block[]
43
+ interface ImageField extends BaseField {
44
+ type: 'image';
45
+ }
46
+
47
+ export interface BlocksField extends BaseField {
48
+ type: 'blocks';
49
+ children: Record<string, BlockDef | FieldDef>;
50
+ }
51
+
52
+ export type FieldDef = TextField | ImageField | BlocksField;
53
+
54
+ export interface BlockDef {
55
+ label: string;
56
+ type: string;
57
+ fields: Record<string, FieldDef>;
58
+ description?: string
59
+ }
60
+
61
+ type DBDefaults = {
62
+ id: number
63
+ created_at: string
64
+ updated_at: string
65
+ name: string
66
+ label: string
67
+ // type: string
68
+ sort_order: number
69
+ value: string
70
+ options: string | null
71
+ status: 'enabled' | 'disabled'
72
+ parent_id: number | null
73
+ depth: number
74
+ }
75
+
76
+ export type DBBlockResult = {
77
+ id: number
78
+ created_at: string
79
+ updated_at: string
80
+ name: string
81
+ label: string
82
+ type: string
83
+ sort_order: number
84
+ value: string | null
85
+ options: any
86
+ status: string
87
+ parent_id: number | null
88
+ depth: number
89
+ children?: DBBlockResult[]
90
+ fields?: Record<string, DBBlockResult>
91
+ }
12
92
 
13
93
  export type DBBlock = Block & {
14
94
  id: number
@@ -16,10 +96,20 @@ export type DBBlock = Block & {
16
96
  updated_at: string
17
97
  value: string | null
18
98
  sort_order: number | null
19
- parent_block_id: number | null
99
+ parent_id: number | null
20
100
  options: number | null
21
101
  }
22
102
 
103
+ export type BlockStatus = 'enabled' | 'disabled'
104
+
23
105
  export type StudioConfig = {
106
+ siteName: string
24
107
  honoConfig?: HonoOptions<BlankEnv>
108
+ structure: Structure
25
109
  }
110
+
111
+ export type RequestContext = Context<
112
+ { Bindings: HttpBindings },
113
+ string,
114
+ BlankInput
115
+ >
@@ -6,7 +6,7 @@ type Block = {
6
6
  sort_order: number
7
7
  value: string | null
8
8
  options: any // JSON-parsed if necessary
9
- parent_block_id: number | null
9
+ parent_id: number | null
10
10
  depth: number
11
11
  // ... you can add other fields if needed
12
12
  }
@@ -26,13 +26,13 @@ export function buildBlockTree(blocks: Block[]): BlockWithChildren {
26
26
  for (const block of blocks) {
27
27
  const current = blockMap.get(block.id)!
28
28
 
29
- if (block.parent_block_id != null) {
30
- const parent = blockMap.get(block.parent_block_id)
29
+ if (block.parent_id != null) {
30
+ const parent = blockMap.get(block.parent_id)
31
31
  if (parent) {
32
32
  parent.fields.push(current)
33
33
  } else {
34
34
  console.warn(
35
- `Parent with id ${block.parent_block_id} not found for block ${block.id}`,
35
+ `Parent with id ${block.parent_id} not found for block ${block.id}`,
36
36
  )
37
37
  }
38
38
  } else {
package/utils/define.ts CHANGED
@@ -1,13 +1,29 @@
1
- import { type Context } from 'hono'
2
1
  import * as types from '../types.ts'
3
- import { type HttpBindings } from '@hono/node-server'
4
- import { type BlankInput } from 'hono/types'
5
2
  import { type HtmlEscapedString } from './html.ts'
6
3
 
7
4
  export const defineConfig = (config: types.StudioConfig) => config
8
- export const defineStructure = (structure: types.Structure) => structure
5
+
6
+ // export const defineStructure = (structure: types.Block[]) => structure
7
+ // export const defineField = (field: types.Field) => field
8
+ // export const defineBlock = (block: types.Block) => block
9
+
9
10
  export const defineEntry = (
10
11
  fn: (
11
- c: Context<{ Bindings: HttpBindings }, string, BlankInput>,
12
+ c: types.RequestContext,
12
13
  ) => HtmlEscapedString | Promise<HtmlEscapedString>,
13
14
  ) => fn
15
+
16
+ // --- Identity helpers (preserve literal types) ---
17
+ export function defineField(field: types.FieldDef) {
18
+ return field
19
+ }
20
+
21
+ export function defineBlock(block: types.BlockDef) {
22
+ return block
23
+ }
24
+
25
+ export function defineStructure(
26
+ structure: Record<string, types.BlockDef>,
27
+ ) {
28
+ return structure
29
+ }
@@ -9,7 +9,15 @@ export const fileBasedRouter = async (rootdir: string) => {
9
9
  const router = new Hono()
10
10
 
11
11
  const root = path.resolve(rootdir)
12
- const dirs = await fs.readdir(root, { recursive: true })
12
+
13
+ let dirs
14
+
15
+ try {
16
+ dirs = await fs.readdir(root, { recursive: true })
17
+ } catch (error) {
18
+ return
19
+ }
20
+
13
21
  const files = dirs.filter((dir) => path.extname(dir))
14
22
 
15
23
  await Promise.all(
@@ -3,15 +3,6 @@ import path from 'node:path'
3
3
 
4
4
  const CONFIG_FILE_NAME = 'alstar.config.ts'
5
5
 
6
- async function fileExists(filepath: string) {
7
- // does the file exist?
8
- try {
9
- await fs.stat(filepath)
10
- } catch (error) {
11
- return null
12
- }
13
- }
14
-
15
6
  export const getConfig = async <P>(): Promise<P> => {
16
7
  const root = path.resolve('./')
17
8
 
@@ -24,3 +15,11 @@ export const getConfig = async <P>(): Promise<P> => {
24
15
 
25
16
  return config as P
26
17
  }
18
+
19
+ async function fileExists(filepath: string) {
20
+ try {
21
+ return await fs.stat(filepath)
22
+ } catch (error) {
23
+ return null
24
+ }
25
+ }
@@ -0,0 +1,28 @@
1
+ import { db } from '@alstar/db'
2
+ import { query } from '../queries/index.ts'
3
+ import type { Block, FieldDef } from '../types.ts'
4
+
5
+ export function getOrCreateRow(
6
+ parentId: string | number,
7
+ name: string,
8
+ field: Block | FieldDef,
9
+ sortOrder: number,
10
+ ) {
11
+ const data = query.block({
12
+ parent_id: parentId?.toString() || null,
13
+ name: name,
14
+ sort_order: sortOrder.toString(),
15
+ })
16
+
17
+ if (data) return data
18
+
19
+ const change = db.insertInto('blocks', {
20
+ name: name?.toString(),
21
+ label: field.label?.toString(),
22
+ type: field.type?.toString(),
23
+ sort_order: sortOrder,
24
+ parent_id: parentId,
25
+ })
26
+
27
+ return query.block({ id: change.lastInsertRowid.toString() })
28
+ }
@@ -0,0 +1,9 @@
1
+ import packageJSON from '../package.json' with { type: 'json' }
2
+
3
+ export default () => {
4
+ console.log('\x1b[32m%s\x1b[0m', '╭───────────────────────╮')
5
+ console.log('\x1b[32m%s\x1b[0m', '│ Alstar Studio │')
6
+ console.log('\x1b[32m%s\x1b[0m', `│ ${packageJSON.version}${' '.repeat(22 - packageJSON.version.length)}│`)
7
+ console.log('\x1b[32m%s\x1b[0m', `│ http://localhost:${3000} │`)
8
+ console.log('\x1b[32m%s\x1b[0m', '╰───────────────────────╯')
9
+ }
@@ -1,59 +0,0 @@
1
- .admin-panel {
2
- /* background: hsla(0, 0%, 0%, 0.1); */
3
- padding: 40px;
4
- padding-right: 0;
5
-
6
- height: 100%;
7
- min-height: inherit;
8
-
9
- min-width: 200px;
10
-
11
- > h1 {
12
- padding-bottom: 1rem;
13
-
14
- a {
15
- display: flex;
16
- }
17
-
18
- svg {
19
- height: 1.6rem;
20
- }
21
- }
22
-
23
- form {
24
- padding-bottom: 1rem;
25
-
26
- button {
27
- margin: 10px 0px 20px;
28
- }
29
- }
30
-
31
- #entries ul {
32
- padding: 0;
33
-
34
- > li {
35
- margin-bottom: 0px;
36
- border-radius: 8px;
37
- display: flex;
38
- justify-content: space-between;
39
- align-items: stretch;
40
- /* align-items: center; */
41
- list-style: none;
42
- margin-inline: -1rem;
43
-
44
- a {
45
- text-decoration: none;
46
- width: 100%;
47
- padding: 0.5rem 1rem;
48
- }
49
-
50
- button {
51
- border-radius: 7px;
52
-
53
- svg {
54
- margin: 0.5rem 1rem;
55
- }
56
- }
57
- }
58
- }
59
- }
@@ -1,164 +0,0 @@
1
- import { html } from 'hono/html'
2
- import { type Block } from '../types.ts'
3
- import { type HtmlEscapedString } from 'hono/utils/html'
4
- import { query } from '../queries/index.ts'
5
- import { db } from '@alstar/db'
6
- import BlockComponent from './Block.ts'
7
- import {
8
- buildStructurePath,
9
- type StructurePath,
10
- } from '../utils/build-structure-path.ts'
11
-
12
- function getData(parentId: string | number, field: Block, sortOrder: number) {
13
- const data = query.block({
14
- parent: parentId?.toString() || null,
15
- name: field.name,
16
- sort_order: sortOrder.toString(),
17
- })
18
-
19
- if (!data) {
20
- const change = db.insertInto('blocks', {
21
- name: field.name?.toString(),
22
- label: field.label?.toString(),
23
- type: field.type?.toString(),
24
- sort_order: sortOrder,
25
- parent_block_id: parentId,
26
- })
27
-
28
- return query.block({ id: change.lastInsertRowid.toString() })
29
- }
30
-
31
- return data
32
- }
33
-
34
- const Field = (props: {
35
- entryId: string | number
36
- parentId: string | number
37
- blockStructure: Block
38
- sortOrder?: number
39
- structurePath: StructurePath
40
- }): HtmlEscapedString | Promise<HtmlEscapedString> => {
41
- const {
42
- entryId,
43
- parentId,
44
- blockStructure,
45
- sortOrder = 0,
46
- structurePath,
47
- } = props
48
-
49
- const data = getData(parentId, blockStructure, sortOrder)
50
-
51
- if (!data) return html`<p>No block</p>`
52
-
53
- const fieldStructurePath = buildStructurePath(blockStructure, structurePath)
54
-
55
- return html`
56
- ${blockStructure.type === 'slug' &&
57
- html`
58
- <form
59
- data-on-input="@patch('/admin/api/block', { contentType: 'form' })"
60
- >
61
- <label for="block-${data.id}">${blockStructure.label}</label>
62
- <input
63
- id="block-${data.id}"
64
- name="value"
65
- type="text"
66
- value="${data.value}"
67
- />
68
-
69
- <input type="hidden" name="type" value="${blockStructure.type}" />
70
- <input type="hidden" name="id" value="${data.id}" />
71
- <input type="hidden" name="entryId" value="${entryId}" />
72
- <input type="hidden" name="parentId" value="${parentId}" />
73
- <input type="hidden" name="sort_order" value="${sortOrder}" />
74
- <input
75
- type="hidden"
76
- name="path"
77
- value="${fieldStructurePath.join('.')}"
78
- />
79
- </form>
80
- `}
81
- ${blockStructure.type === 'text' &&
82
- html`
83
- <form
84
- data-on-input="@patch('/admin/api/block', { contentType: 'form' })"
85
- >
86
- <label for="block-${data.id}">${blockStructure.label}</label>
87
- <input
88
- id="block-${data.id}"
89
- name="value"
90
- type="text"
91
- value="${data.value}"
92
- />
93
-
94
- <input type="hidden" name="type" value="${blockStructure.type}" />
95
- <input type="hidden" name="id" value="${data.id}" />
96
- <input type="hidden" name="entryId" value="${entryId}" />
97
- <input type="hidden" name="parentId" value="${parentId}" />
98
- <input type="hidden" name="sort_order" value="${sortOrder}" />
99
- <input
100
- type="hidden"
101
- name="path"
102
- value="${fieldStructurePath.join('.')}"
103
- />
104
- </form>
105
- `}
106
- ${blockStructure.type === 'image' &&
107
- html`
108
- <form
109
- data-on-input="@patch('/admin/api/block', { contentType: 'form' })"
110
- >
111
- <label for="block-${data.id}">${blockStructure.label}</label>
112
- <input
113
- id="block-${data.id}"
114
- name="value"
115
- type="text"
116
- value="${data.value}"
117
- />
118
-
119
- <input type="hidden" name="type" value="${blockStructure.type}" />
120
- <input type="hidden" name="id" value="${data.id}" />
121
- <input type="hidden" name="entryId" value="${entryId}" />
122
- <input type="hidden" name="parentId" value="${parentId}" />
123
- <input type="hidden" name="sort_order" value="${sortOrder}" />
124
- <input
125
- type="hidden"
126
- name="path"
127
- value="${fieldStructurePath.join('.')}"
128
- />
129
- </form>
130
- `}
131
- ${blockStructure.type === 'markdown' &&
132
- html`
133
- <form
134
- data-on-input="@patch('/admin/api/block', { contentType: 'form' })"
135
- >
136
- <label for="block-${data.id}">${blockStructure.label}</label>
137
-
138
- <textarea></textarea>
139
-
140
- <!-- <input
141
- id="block-${data.id}"
142
- name="value"
143
- type="text"
144
- value="${data.value}"
145
- /> -->
146
-
147
- <input type="hidden" name="type" value="${blockStructure.type}" />
148
- <input type="hidden" name="id" value="${data.id}" />
149
- <input type="hidden" name="entryId" value="${entryId}" />
150
- <input type="hidden" name="parentId" value="${parentId}" />
151
- <input type="hidden" name="sort_order" value="${sortOrder}" />
152
- <input
153
- type="hidden"
154
- name="path"
155
- value="${fieldStructurePath.join('.')}"
156
- />
157
- </form>
158
- `}
159
- ${blockStructure.type === 'blocks' &&
160
- BlockComponent(entryId, data.id, blockStructure, fieldStructurePath)}
161
- `
162
- }
163
-
164
- export default Field