@alstar/studio 0.0.0-beta.16 → 0.0.0-beta.18

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 (49) hide show
  1. package/api/block.ts +0 -14
  2. package/components/AdminPanel.ts +11 -5
  3. package/components/BlockFieldRenderer.ts +25 -19
  4. package/components/BlockRenderer.ts +4 -4
  5. package/components/Entries.ts +1 -1
  6. package/components/Entry.ts +13 -7
  7. package/components/FieldRenderer.ts +8 -7
  8. package/components/LivePreview.ts +37 -0
  9. package/components/Render.ts +2 -2
  10. package/components/SiteLayout.ts +1 -4
  11. package/components/fields/Markdown.ts +10 -3
  12. package/components/fields/Reference.ts +11 -7
  13. package/components/fields/Slug.ts +6 -6
  14. package/components/fields/Text.ts +13 -8
  15. package/components/icons.ts +3 -0
  16. package/components/settings/ApiKeys.ts +4 -4
  17. package/components/settings/Backup.ts +3 -3
  18. package/components/settings/Users.ts +1 -1
  19. package/index.ts +11 -10
  20. package/package.json +4 -5
  21. package/pages/entry/[id].ts +7 -1
  22. package/pages/error.ts +7 -6
  23. package/pages/login.ts +1 -1
  24. package/pages/register.ts +2 -2
  25. package/public/studio/css/admin-panel.css +27 -9
  26. package/public/studio/css/blocks-field.css +25 -0
  27. package/public/studio/css/entry-page.css +4 -0
  28. package/public/studio/css/entry.css +35 -0
  29. package/public/studio/css/field.css +14 -0
  30. package/public/studio/css/live-preview.css +25 -0
  31. package/public/studio/css/settings.css +4 -0
  32. package/public/studio/js/live-preview.js +26 -0
  33. package/public/studio/js/markdown-editor.js +6 -0
  34. package/public/studio/js/sortable-list.js +6 -4
  35. package/public/studio/main.css +11 -13
  36. package/public/studio/main.js +1 -0
  37. package/queries/block.ts +127 -105
  38. package/queries/index.ts +3 -2
  39. package/types.ts +39 -69
  40. package/utils/define.ts +3 -1
  41. package/utils/refresher.ts +56 -0
  42. package/utils/renderSSE.ts +8 -3
  43. package/utils/startup-log.ts +4 -4
  44. package/queries/block-2.ts +0 -339
  45. package/queries/db-types.ts +0 -15
  46. package/queries/getBlockTrees-2.ts +0 -71
  47. package/queries/getBlocks.ts +0 -214
  48. package/queries/structure-types.ts +0 -97
  49. package/utils/buildBlocksTree.ts +0 -44
package/api/block.ts CHANGED
@@ -5,7 +5,6 @@ import { streamSSE } from 'hono/streaming'
5
5
  import { sql } from '../utils/sql.ts'
6
6
  import { db } from '@alstar/db'
7
7
  import {
8
- blockWithChildren,
9
8
  deleteBlockWithChildren,
10
9
  } from '../queries/block-with-children.ts'
11
10
  import { query } from '../queries/index.ts'
@@ -57,19 +56,6 @@ app.patch('/block', async (c) => {
57
56
  transaction.run(value, id)
58
57
 
59
58
  await renderSSE(stream, c)
60
-
61
- // if (entryId === parentId && name?.toString() === 'title') {
62
- // const rootBlock = query.block({
63
- // id: parentId?.toString() || null,
64
- // })
65
-
66
- // if (rootBlock.type !== 'single') {
67
- // await stream.writeSSE({
68
- // event: 'datastar-patch-elements',
69
- // data: `elements <a href="/studio/entry/${entryId}" id="block_link_${entryId}">${value}</a>`,
70
- // })
71
- // }
72
- // }
73
59
  })
74
60
  })
75
61
 
@@ -2,7 +2,7 @@ import { html } from 'hono/html'
2
2
  import { logo } from './icons.ts'
3
3
  import Entries from './Entries.ts'
4
4
  import * as icons from './icons.ts'
5
- import { studioStructure } from '../index.ts'
5
+ import { studioConfig, studioStructure } from '../index.ts'
6
6
  import { getOrCreateRow } from '../utils/get-or-create-row.ts'
7
7
 
8
8
  export default () => {
@@ -10,9 +10,15 @@ export default () => {
10
10
 
11
11
  return html`
12
12
  <div class="admin-panel" id="admin_panel">
13
- <h1>
14
- <a href="/studio" aria-label="Go to dashboard"> ${logo} </a>
15
- </h1>
13
+ <!-- <button class="ghost toggle-button">
14
+ {icons.bars}
15
+ </button> -->
16
+
17
+ <header>
18
+ <h1 class="title">
19
+ <a href="/studio" aria-label="Go to dashboard"> ${studioConfig.admin?.logo ?? logo} </a>
20
+ </h1>
21
+ </header>
16
22
 
17
23
  <aside style="width: 100%;">
18
24
  ${entries.map(([name, block]) => {
@@ -37,7 +43,7 @@ export default () => {
37
43
 
38
44
  return html`
39
45
  <form
40
- data-on-submit="@post('/studio/api/block', {
46
+ data-on:submit="@post('/studio/api/block', {
41
47
  contentType: 'form',
42
48
  headers: {
43
49
  'render': 'AdminPanel',
@@ -1,5 +1,5 @@
1
1
  import { query } from '../queries/index.ts'
2
- import type { BlocksFieldDefStructure } from '../types.ts'
2
+ import type { BlocksFieldDef, BlocksFieldDefStructure } from '../types.ts'
3
3
  import { BlockInstance } from '../utils/define.ts'
4
4
  import { getOrCreateRow } from '../utils/get-or-create-row.ts'
5
5
  import { html } from '../utils/html.ts'
@@ -7,8 +7,8 @@ import * as icons from './icons.ts'
7
7
  import Render from './Render.ts'
8
8
 
9
9
  export default (props: {
10
- entryId: number
11
- parentId: number
10
+ entryId: number | string
11
+ parentId: number | string
12
12
  name: string
13
13
  structure: BlocksFieldDefStructure
14
14
  id?: number
@@ -32,7 +32,7 @@ export default (props: {
32
32
 
33
33
  return html`
34
34
  <div class="blocks-field">
35
- <header>
35
+ <header data-on:click="console.log('hehehe')">
36
36
  <p>${structure.label}</p>
37
37
 
38
38
  <details class="dropdown">
@@ -42,10 +42,10 @@ export default (props: {
42
42
  return html`
43
43
  <li>
44
44
  <form
45
- data-on-submit="@post('/studio/api/block', {
45
+ data-on:submit="@post('/studio/api/block', {
46
46
  contentType: 'form',
47
47
  headers: {
48
- render: 'Entry',
48
+ render: 'Entry LivePreview',
49
49
  props: '${JSON.stringify({ entryId: entryId })}'
50
50
  }
51
51
  })"
@@ -69,8 +69,6 @@ export default (props: {
69
69
  </details>
70
70
  </header>
71
71
 
72
- <hr style="margin-top: 0;" />
73
-
74
72
  <sortable-list data-id="${data.id}">
75
73
  ${rows.map((row) => {
76
74
  const [name, struct] =
@@ -79,7 +77,7 @@ export default (props: {
79
77
  if (!name || !struct) return html`<p>No name</p>`
80
78
 
81
79
  return html`
82
- <article data-id="${row.id}">
80
+ <article data-id="${row.id}" data-signals="{ 'expanded-${row.id}': true }">
83
81
  <header>
84
82
  ${struct.label}
85
83
 
@@ -88,19 +86,25 @@ export default (props: {
88
86
  <input name="enable" type="checkbox" role="switch" checked />
89
87
  </label> -->
90
88
 
89
+ <button data-on:click="$expanded-${row.id} = !$expanded-${row.id}" class="ghost handle text-secondary" data-tooltip="Collapse" data-placement="top">
90
+ ${icons.minus}
91
+ </button>
92
+
91
93
  <button
92
94
  data-handle-for="${data.id}"
93
95
  class="ghost handle text-secondary"
94
96
  style="cursor: grab"
97
+ data-tooltip="Reorder"
98
+ data-placement="top"
95
99
  >
96
100
  ${icons.bars}
97
101
  </button>
98
102
 
99
103
  <form
100
- data-on-submit="@delete('/studio/api/block', {
104
+ data-on:submit="@delete('/studio/api/block', {
101
105
  contentType: 'form',
102
106
  headers: {
103
- render: 'Entry',
107
+ render: 'Entry LivePreview',
104
108
  props: '${JSON.stringify({ entryId: entryId })}'
105
109
  }
106
110
  })"
@@ -120,14 +124,16 @@ export default (props: {
120
124
  </aside>
121
125
  </header>
122
126
 
123
- ${Render({
124
- entryId,
125
- parentId:
126
- struct.instanceOf === BlockInstance ? row.id : data.id,
127
- id: row.id,
128
- structure: struct,
129
- name: name,
130
- })}
127
+ <div data-show="$expanded-${row.id}">
128
+ ${Render({
129
+ entryId,
130
+ parentId:
131
+ struct.instanceOf === BlockInstance ? row.id : data.id,
132
+ id: row.id,
133
+ structure: struct,
134
+ name: name,
135
+ })}
136
+ </div>
131
137
  </article>
132
138
  `
133
139
  })}
@@ -1,12 +1,12 @@
1
1
  import { html } from 'hono/html'
2
- import type { BlockDef } from '../types.ts'
2
+ import type { BlockDefStructure } from '../types.ts'
3
3
  import Render from './Render.ts'
4
4
 
5
5
  export default (props: {
6
- entryId: number
7
- parentId: number
6
+ entryId: number | string
7
+ parentId: number | string
8
8
  id?: number
9
- structure: BlockDef
9
+ structure: BlockDefStructure
10
10
  }) => {
11
11
  const { entryId, parentId, structure } = props
12
12
 
@@ -21,7 +21,7 @@ export default ({ name }: { name: string }) => {
21
21
  </a>
22
22
 
23
23
  <form
24
- data-on-submit="@delete('/studio/api/block', {
24
+ data-on:submit="@delete('/studio/api/block', {
25
25
  contentType: 'form',
26
26
  headers: {
27
27
  render: 'AdminPanel'
@@ -3,7 +3,7 @@ import { query } from '../queries/index.ts'
3
3
  import { studioStructure } from '../index.ts'
4
4
  import Render from './Render.ts'
5
5
 
6
- export default (props: { entryId: number }) => {
6
+ export default (props: { entryId: number | string }) => {
7
7
  const data = query.block({ id: props.entryId?.toString() })
8
8
 
9
9
  if (!data) return html`<p>No entry with id: "${props.entryId}"</p>`
@@ -14,12 +14,18 @@ export default (props: { entryId: number }) => {
14
14
 
15
15
  return html`
16
16
  <div id="entry" class="entry">
17
- ${Render({
18
- entryId: props.entryId,
19
- parentId: props.entryId,
20
- structure: structure,
21
- name: data.name,
22
- })}
17
+ <header>
18
+ <h1>Entry content</h1>
19
+ </header>
20
+
21
+ <div class="content">
22
+ ${Render({
23
+ entryId: props.entryId,
24
+ parentId: props.entryId,
25
+ structure: structure,
26
+ name: data.name,
27
+ })}
28
+ </div>
23
29
  </div>
24
30
 
25
31
  `
@@ -2,10 +2,11 @@ import { Field } from './fields/index.ts'
2
2
  import type { BlocksFieldDefStructure, FieldDefStructure } from '../types.ts'
3
3
  import BlockFieldRenderer from './BlockFieldRenderer.ts'
4
4
  import { BlockFieldInstance } from '../utils/define.ts'
5
+ import { html } from 'hono/html'
5
6
 
6
7
  export default (props: {
7
- entryId: number
8
- parentId: number
8
+ entryId: number | string
9
+ parentId: number | string
9
10
  structure: FieldDefStructure | BlocksFieldDefStructure
10
11
  id?: number
11
12
  name: string
@@ -18,23 +19,23 @@ export default (props: {
18
19
 
19
20
  switch (structure.type) {
20
21
  case 'text': {
21
- return Field.Text({ entryId, parentId, name, id, structure })
22
+ return html`<div class="field">${Field.Text({ entryId, parentId, name, id, structure })}</div>`
22
23
  }
23
24
 
24
25
  case 'slug': {
25
- return Field.Slug({ entryId, parentId, name, id, structure })
26
+ return html`<div class="field">${Field.Slug({ entryId, parentId, name, id, structure })}</div>`
26
27
  }
27
28
 
28
29
  case 'markdown': {
29
- return Field.Markdown({ entryId, parentId, name, id, structure })
30
+ return html`<div class="field">${Field.Markdown({ entryId, parentId, name, id, structure })}</div>`
30
31
  }
31
32
 
32
33
  case 'image': {
33
- return Field.Text({ entryId, parentId, name, structure, id })
34
+ return html`<div class="field">${Field.Text({ entryId, parentId, name, structure, id })}</div>`
34
35
  }
35
36
 
36
37
  case 'reference': {
37
- return Field.Reference({ entryId, parentId, name, structure, id })
38
+ return html`<div class="field">${Field.Reference({ entryId, parentId, name, structure, id })}</div>`
38
39
  }
39
40
  }
40
41
  }
@@ -0,0 +1,37 @@
1
+ import { html } from "hono/html"
2
+ import { query } from "../queries/index.ts"
3
+ import { studioConfig, studioStructure } from "../index.ts"
4
+
5
+ export default (props: { entryId: number | string }) => {
6
+ const data = query.root({ id: props.entryId })
7
+
8
+ if (!data) return html`<p>No entry with id: "${props.entryId}"</p>`
9
+
10
+ const structure = studioStructure[data.name]
11
+
12
+ if (!structure) return html`<p>No structure of type: ${data.name}</p>`
13
+
14
+ if (!structure.preview) return html``
15
+
16
+ const slugValue = 'slug' in structure.preview! && structure.preview?.slug
17
+ const slugColumn = 'field' in structure.preview! && structure.preview?.field
18
+
19
+ if (!slugValue && !slugColumn) return html``
20
+
21
+ let slug
22
+
23
+ if (slugValue) {
24
+ slug = slugValue
25
+ } else if (slugColumn) {
26
+ slug = data.fields[slugColumn].value
27
+ }
28
+
29
+ if (!slug) return html``
30
+
31
+ return html`<live-preview id="live_preview" class="live-preview" data-rendered-at="${Date.now()}">
32
+ <header>
33
+ <h1>Live preview</h1>
34
+ </header>
35
+ <iframe src="http://localhost:${studioConfig.port}/${slug === '/' ? '' : slug}"></iframe>
36
+ </live-preview>`
37
+ }
@@ -15,8 +15,8 @@ import type {
15
15
  } from '../types.ts'
16
16
 
17
17
  export default (props: {
18
- entryId: number
19
- parentId: number
18
+ entryId: number | string
19
+ parentId: number | string
20
20
  structure: BlockDefStructure | FieldDefStructure | BlocksFieldDefStructure
21
21
  id?: number
22
22
  name: string
@@ -25,10 +25,7 @@ export default (
25
25
 
26
26
  <meta name="color-scheme" content="light dark" />
27
27
 
28
- <script
29
- type="module"
30
- src="https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"
31
- ></script>
28
+ <script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.0-RC.6/bundles/datastar.js"></script>
32
29
 
33
30
  <script type="importmap">
34
31
  {
@@ -3,8 +3,8 @@ import { getOrCreateRow } from '../../utils/get-or-create-row.ts'
3
3
  import { html } from '../../utils/html.ts'
4
4
 
5
5
  export default (props: {
6
- entryId: number
7
- parentId: number
6
+ entryId: number | string
7
+ parentId: number | string
8
8
  name: string
9
9
  id?: number
10
10
  structure: FieldDefStructure
@@ -17,7 +17,13 @@ export default (props: {
17
17
 
18
18
  return html`
19
19
  <form
20
- data-on-input="@patch('/studio/api/block', { contentType: 'form' })"
20
+ data-on:input="@patch('/studio/api/block', {
21
+ contentType: 'form',
22
+ headers: {
23
+ render: 'LivePreview',
24
+ props: '${JSON.stringify({ entryId: entryId })}'
25
+ }
26
+ })"
21
27
  >
22
28
  <hgroup>
23
29
  <label for="block-${data.id}">${structure.label}</label>
@@ -27,6 +33,7 @@ export default (props: {
27
33
  <markdown-editor
28
34
  data-content="${data.value?.trim()}"
29
35
  data-id="${data.id}"
36
+ data-entry-id="${entryId}"
30
37
  >
31
38
  <!-- <textarea id="block-{data.id}" name="value" class="markdown">
32
39
  {data.value}
@@ -4,8 +4,8 @@ import type { FieldDefStructure, ReferenceFieldStructure } from '../../types.ts'
4
4
  import { query } from '../../queries/index.ts'
5
5
 
6
6
  export default (props: {
7
- entryId: number
8
- parentId: number
7
+ entryId: number | string
8
+ parentId: number | string
9
9
  name: string
10
10
  id?: number
11
11
  structure: ReferenceFieldStructure
@@ -23,14 +23,15 @@ export default (props: {
23
23
 
24
24
  if (!data) return html`<p>No block</p>`
25
25
 
26
- const entries = query.roots({ type: structure.to }, { depth: 1 })
26
+ const entries = query.blocks({ type: structure.to })
27
27
 
28
28
  return html`
29
29
  <form
30
- data-on-input="@patch('/studio/api/block', {
30
+ data-on:input="@patch('/studio/api/block', {
31
31
  contentType: 'form',
32
32
  headers: {
33
- render: ''
33
+ render: 'LivePreview',
34
+ props: '${JSON.stringify({ entryId: entryId })}'
34
35
  }
35
36
  })"
36
37
  >
@@ -50,8 +51,11 @@ export default (props: {
50
51
  />
51
52
  <datalist id="entries-${data.id}">
52
53
  ${entries.map((entry) => {
53
- return html`<option value="${entry.fields.slug.value}">
54
- ${entry.fields.title.value}
54
+ const slug = query.block({ name: 'slug', parent_id: entry.id })
55
+ const title = query.block({ name: 'title', parent_id: entry.id })
56
+
57
+ return html`<option value="${slug.value}">
58
+ ${title.value}
55
59
  </option>`
56
60
  })}
57
61
  </datalist>
@@ -43,8 +43,8 @@ app.get('/slug', async (c) => {
43
43
  export const routes = app
44
44
 
45
45
  export default (props: {
46
- entryId: number
47
- parentId: number
46
+ entryId: number | string
47
+ parentId: number | string
48
48
  name: string
49
49
  id?: number
50
50
  structure: FieldDefStructure
@@ -69,10 +69,10 @@ export default (props: {
69
69
  return html`
70
70
  <div style="display: flex; align-items: center">
71
71
  <form
72
- data-on-change="@patch('/studio/api/block', {
72
+ data-on:change="@patch('/studio/api/block', {
73
73
  contentType: 'form',
74
74
  headers: {
75
- render: 'Entry',
75
+ render: 'Entry LivePreview',
76
76
  props: '${JSON.stringify({ entryId: entryId })}'
77
77
  }
78
78
  })"
@@ -98,10 +98,10 @@ export default (props: {
98
98
 
99
99
  <form
100
100
  style="margin-top: 21px"
101
- data-on-submit="@patch('/studio/api/block', {
101
+ data-on:submit="@patch('/studio/api/block', {
102
102
  contentType: 'form',
103
103
  headers: {
104
- render: 'Entry',
104
+ render: 'Entry LivePreview',
105
105
  props: '${JSON.stringify({ entryId: entryId })}'
106
106
  }
107
107
  })"
@@ -1,10 +1,11 @@
1
1
  import { getOrCreateRow } from '../../utils/get-or-create-row.ts'
2
2
  import { html } from '../../utils/html.ts'
3
3
  import type { FieldDefStructure } from '../../types.ts'
4
+ import { raw } from 'hono/html'
4
5
 
5
6
  export default (props: {
6
- entryId: number
7
- parentId: number
7
+ entryId: number | string
8
+ parentId: number | string
8
9
  name: string
9
10
  id?: number
10
11
  structure: FieldDefStructure
@@ -26,21 +27,25 @@ export default (props: {
26
27
 
27
28
  return html`
28
29
  <form
29
- data-on-input="@patch('/studio/api/block', {
30
+ class="field-text"
31
+ data-on:input="@patch('/studio/api/block', {
30
32
  contentType: 'form',
31
33
  headers: {
32
- render: '${isEntryTitle ? 'AdminPanel' : ''}'
34
+ render: '${isEntryTitle ? 'AdminPanel' : ''} LivePreview',
35
+ props: '${JSON.stringify({ entryId: entryId })}'
33
36
  }
34
37
  })"
35
38
  >
36
39
  <hgroup>
37
40
  <label for="block-${data.id}">${structure.label}</label>
38
- ${structure.description &&
39
- html`
40
- <p><small>${structure.description}</small></p>
41
- `}
41
+ ${structure.description ?
42
+ html`
43
+ <p><small>${structure.description}</small></p>
44
+ ` : null}
42
45
  </hgroup>
43
46
 
47
+ ${structure.presentation === 'svg' ? html`<output>${raw(data.value)}</output>`: ''}
48
+
44
49
  <input
45
50
  id="block-${data.id}"
46
51
  name="value"
@@ -249,3 +249,6 @@ export const download = html`
249
249
  </g>
250
250
  </svg>
251
251
  `
252
+
253
+ export const minus = html`
254
+ <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 20 20"><!-- Icon from HeroIcons by Refactoring UI Inc - https://github.com/tailwindlabs/heroicons/blob/master/LICENSE --><path fill="currentColor" d="M6.75 9.25a.75.75 0 0 0 0 1.5h6.5a.75.75 0 0 0 0-1.5z"/></svg>`
@@ -33,7 +33,7 @@ export default () => {
33
33
  <td><input type="text" disabled value="${apiKey.hint}" /></td>
34
34
  <td>
35
35
  <form
36
- data-on-submit="@delete('/studio/api/api-key', {
36
+ data-on:submit="@delete('/studio/api/api-key', {
37
37
  contentType: 'form',
38
38
  headers: {
39
39
  render: 'Settings'
@@ -58,7 +58,7 @@ export default () => {
58
58
  </table>
59
59
 
60
60
  <form
61
- data-on-submit="@post('/studio/api/api-key', {
61
+ data-on:submit="@post('/studio/api/api-key', {
62
62
  contentType: 'form',
63
63
  headers: {
64
64
  render: 'Settings'
@@ -93,7 +93,7 @@ export default () => {
93
93
  <button
94
94
  style="display: flex; align-items: center;"
95
95
  data-attr="{ id: $apiKey }"
96
- data-on-click="navigator.clipboard.writeText($apiKey); $copied = true"
96
+ data-on:click="navigator.clipboard.writeText($apiKey); $copied = true"
97
97
  class="ghost"
98
98
  aria-label="Copy key to clipboard"
99
99
  >
@@ -110,7 +110,7 @@ export default () => {
110
110
  <footer>
111
111
  <button
112
112
  class="ghost"
113
- data-on-click="$apiKey = ''; $copied = false; evt.target.closest('dialog')?.close()"
113
+ data-on:click="$apiKey = ''; $copied = false; evt.target.closest('dialog')?.close()"
114
114
  >
115
115
  Close
116
116
  </button>
@@ -41,7 +41,7 @@ export default async () => {
41
41
  </th>
42
42
  <th>
43
43
  <form
44
- data-on-submit="@delete('/studio/api/backup', {
44
+ data-on:submit="@delete('/studio/api/backup', {
45
45
  contentType: 'form',
46
46
  headers: {
47
47
  render: 'Settings'
@@ -59,7 +59,7 @@ export default async () => {
59
59
  </table>
60
60
 
61
61
  <form
62
- data-on-submit="@post('/studio/api/backup', {
62
+ data-on:submit="@post('/studio/api/backup', {
63
63
  contentType: 'form',
64
64
  headers: {
65
65
  render: 'Settings'
@@ -72,7 +72,7 @@ export default async () => {
72
72
  <hr />
73
73
 
74
74
  <form
75
- data-on-submit="@post('/studio/api/backup', { contentType: 'form' })"
75
+ data-on:submit="@post('/studio/api/backup', { contentType: 'form' })"
76
76
  >
77
77
  <input type="file" name="file" />
78
78
  <button type="submit" class="ghost">Restore database</button>
@@ -38,7 +38,7 @@ export default () => {
38
38
  <article>
39
39
  <header>Register user</header>
40
40
  <form
41
- data-on-submit="@post('/studio/api/auth/register', { contentType: 'form' })"
41
+ data-on:submit="@post('/studio/api/auth/register', { contentType: 'form' })"
42
42
  >
43
43
  <label for="register_email"><small>Email</small></label>
44
44
  <input
package/index.ts CHANGED
@@ -6,7 +6,6 @@ import { serveStatic } from '@hono/node-server/serve-static'
6
6
  import { HTTPException } from 'hono/http-exception'
7
7
 
8
8
  import { loadDb } from '@alstar/db'
9
- import { createRefresher } from '@alstar/refresher'
10
9
 
11
10
  import { createStudioTables } from './utils/create-studio-tables.ts'
12
11
  import { fileBasedRouter } from './utils/file-based-router.ts'
@@ -20,21 +19,20 @@ import auth from './utils/auth.ts'
20
19
  import ErrorPage from './pages/error.ts'
21
20
 
22
21
  import * as types from './types.ts'
22
+ import { refresher, refreshClient } from './utils/refresher.ts'
23
23
 
24
24
  export let rootdir = './node_modules/@alstar/studio'
25
25
 
26
26
  export let studioStructure: types.Structure = {}
27
27
  export let studioConfig: types.StudioConfig = {
28
28
  siteName: '',
29
+ honoConfig: {},
29
30
  fileBasedRouter: true,
30
31
  port: 3000,
31
32
  structure: {},
32
33
  }
33
34
 
34
- const createStudio = async (config: types.StudioConfig) => {
35
- // const refresher = await createRefresher({ rootdir: ['.', import.meta.dirname] })
36
- const refresher = await createRefresher({ rootdir: '.' })
37
-
35
+ const createStudio = async (config: types.StudioConfigInput) => {
38
36
  loadDb('./studio.db')
39
37
  createStudioTables()
40
38
 
@@ -48,6 +46,8 @@ const createStudio = async (config: types.StudioConfig) => {
48
46
 
49
47
  const app = new Hono(studioConfig.honoConfig)
50
48
 
49
+ app.get('/refresh', refresher({ root: '.', exclude: '.db' }))
50
+
51
51
  /**
52
52
  * Static folders
53
53
  */
@@ -104,8 +104,6 @@ const createStudio = async (config: types.StudioConfig) => {
104
104
  }),
105
105
  )
106
106
 
107
- // console.log(app.routes)
108
-
109
107
  /**
110
108
  * Run server
111
109
  */
@@ -129,9 +127,12 @@ const createStudio = async (config: types.StudioConfig) => {
129
127
  })
130
128
  })
131
129
 
132
- startupLog({ port: studioConfig.port || 3000, refresherPort: refresher.port })
130
+ startupLog({ port: studioConfig.port })
133
131
 
134
- return app
132
+ return {
133
+ app,
134
+ refreshClient: refreshClient(studioConfig.port)
135
+ }
135
136
  }
136
137
 
137
138
  export {
@@ -144,6 +145,6 @@ export {
144
145
  } from './utils/define.ts'
145
146
  export { type RequestContext } from './types.ts'
146
147
  export { createStudio }
147
- export { html, type HtmlEscapedString } from './utils/html.ts'
148
+ export { html, raw, type HtmlEscapedString } from './utils/html.ts'
148
149
  export { query } from './queries/index.ts'
149
150
  export const version = packageJSON.version