@alstar/studio 0.0.0-beta.1
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/api/block.ts +97 -0
- package/api/index.ts +2 -0
- package/components/AdminPanel/AdminPanel.css +59 -0
- package/components/AdminPanel/AdminPanel.ts +57 -0
- package/components/Block.ts +116 -0
- package/components/Entries.ts +37 -0
- package/components/Entry.css +7 -0
- package/components/Entry.ts +34 -0
- package/components/Field.ts +164 -0
- package/components/Fields.ts +43 -0
- package/components/icons.ts +103 -0
- package/components/index.ts +30 -0
- package/components/layout.ts +53 -0
- package/index.ts +71 -0
- package/package.json +39 -0
- package/public/favicon.svg +6 -0
- package/public/main.css +92 -0
- package/public/main.js +43 -0
- package/queries/index.ts +98 -0
- package/schemas.ts +67 -0
- package/tsconfig.json +3 -0
- package/types.ts +25 -0
- package/utils/build-structure-path.ts +43 -0
- package/utils/buildBlocksTree.ts +44 -0
- package/utils/create-studio-tables.ts +8 -0
- package/utils/file-based-router.ts +58 -0
- package/utils/get-config.ts +26 -0
- package/utils/slugify.ts +10 -0
- package/utils/sql.ts +1 -0
- package/utils/strip-newlines.ts +5 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
type Block = {
|
|
2
|
+
id: number
|
|
3
|
+
name: string
|
|
4
|
+
label: string
|
|
5
|
+
type: string
|
|
6
|
+
sort_order: number
|
|
7
|
+
value: string | null
|
|
8
|
+
options: any // JSON-parsed if necessary
|
|
9
|
+
parent_block_id: number | null
|
|
10
|
+
depth: number
|
|
11
|
+
// ... you can add other fields if needed
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type BlockWithChildren = Block & { fields: BlockWithChildren[] }
|
|
15
|
+
|
|
16
|
+
export function buildBlockTree(blocks: Block[]): BlockWithChildren {
|
|
17
|
+
const blockMap = new Map<number, BlockWithChildren>()
|
|
18
|
+
|
|
19
|
+
// Initialize map with all blocks and empty `fields` array
|
|
20
|
+
for (const block of blocks) {
|
|
21
|
+
blockMap.set(block.id, { ...block, fields: [] })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const tree: BlockWithChildren[] = []
|
|
25
|
+
|
|
26
|
+
for (const block of blocks) {
|
|
27
|
+
const current = blockMap.get(block.id)!
|
|
28
|
+
|
|
29
|
+
if (block.parent_block_id != null) {
|
|
30
|
+
const parent = blockMap.get(block.parent_block_id)
|
|
31
|
+
if (parent) {
|
|
32
|
+
parent.fields.push(current)
|
|
33
|
+
} else {
|
|
34
|
+
console.warn(
|
|
35
|
+
`Parent with id ${block.parent_block_id} not found for block ${block.id}`,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
tree.push(current) // top-level (root) blocks
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return tree[0]
|
|
44
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { Hono } from 'hono'
|
|
4
|
+
import { type HtmlEscapedString } from 'hono/utils/html'
|
|
5
|
+
|
|
6
|
+
type Page<C> = (c?: C) => HtmlEscapedString | Promise<HtmlEscapedString>
|
|
7
|
+
|
|
8
|
+
export const fileBasedRouter = async (rootdir: string) => {
|
|
9
|
+
const router = new Hono()
|
|
10
|
+
|
|
11
|
+
const root = path.resolve(rootdir)
|
|
12
|
+
const dirs = await fs.readdir(root, { recursive: true })
|
|
13
|
+
const files = dirs.filter((dir) => path.extname(dir))
|
|
14
|
+
|
|
15
|
+
await Promise.all(
|
|
16
|
+
files.map(async (file) => {
|
|
17
|
+
const pagePath = path.join(root, file)
|
|
18
|
+
const page = Object.values(await import(pagePath)).at(-1)
|
|
19
|
+
|
|
20
|
+
const relativePageFilePath = pagePath
|
|
21
|
+
.split(rootdir.replace('.', ''))
|
|
22
|
+
.at(-1)
|
|
23
|
+
|
|
24
|
+
if (!relativePageFilePath) return
|
|
25
|
+
|
|
26
|
+
const pageFilePathWithoutExt = relativePageFilePath.replace(
|
|
27
|
+
path.extname(relativePageFilePath),
|
|
28
|
+
'',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if (pageFilePathWithoutExt === '/index') {
|
|
32
|
+
if (typeof page !== 'function') {
|
|
33
|
+
router.get('/', (c) => c.notFound())
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
router.get('/', (c) => c.html((page as Page<typeof c>)(c)))
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const routePath = pageFilePathWithoutExt.replaceAll('/index', '')
|
|
42
|
+
|
|
43
|
+
const route = routePath.replace(
|
|
44
|
+
/\[([^\]]+)\]/g, // [foo] and [bar]
|
|
45
|
+
(_match, content) => `:${content}`, // :foo and :bar
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if (typeof page !== 'function') {
|
|
49
|
+
router.get(route, (c) => c.notFound())
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
router.get(route, (c) => c.html((page as Page<typeof c>)(c)))
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return router
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
const CONFIG_FILE_NAME = 'alstar.config.ts'
|
|
5
|
+
|
|
6
|
+
async function fileExists(filepath: string) {
|
|
7
|
+
// does the file exist?
|
|
8
|
+
try {
|
|
9
|
+
await fs.stat(filepath)
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return {}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const getConfig = async <P>(): Promise<P> => {
|
|
16
|
+
const root = path.resolve('./')
|
|
17
|
+
|
|
18
|
+
if (!(await fileExists(path.join(root, CONFIG_FILE_NAME)))) {
|
|
19
|
+
return {} as P
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const module = await import(path.join(root, CONFIG_FILE_NAME))
|
|
23
|
+
const config = Object.values(module)[0]
|
|
24
|
+
|
|
25
|
+
return config as P
|
|
26
|
+
}
|
package/utils/slugify.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function slugify(str: string) {
|
|
2
|
+
return String(str)
|
|
3
|
+
.normalize('NFKD') // split accented characters into their base characters and diacritical marks
|
|
4
|
+
.replace(/[\u0300-\u036f]/g, '') // remove all the accents, which happen to be all in the \u03xx UNICODE block.
|
|
5
|
+
.trim() // trim leading or trailing whitespace
|
|
6
|
+
.toLowerCase() // convert to lowercase
|
|
7
|
+
.replace(/[^a-z0-9 -]/g, '') // remove non-alphanumeric characters
|
|
8
|
+
.replace(/\s+/g, '-') // replace spaces with hyphens
|
|
9
|
+
.replace(/-+/g, '-') // remove consecutive hyphens
|
|
10
|
+
}
|
package/utils/sql.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const sql = String.raw
|