add layout.sh support

This commit is contained in:
Chris Wanstrath 2025-11-05 11:37:49 -08:00
parent 56362b0ba7
commit 77328f7441
2 changed files with 32 additions and 10 deletions

View File

@ -17,9 +17,9 @@
- [x] Access to query params - [x] Access to query params
- [x] Serve static files in pub/ - [x] Serve static files in pub/
- [x] Working CLI - [x] Working CLI
- [ ] Nice error messages - [x] Nice error messages
- [ ] dev mode / prod mode (caching, errors) - [ ] dev mode / prod mode (caching, errors)
- [ ] Form body parsing for POST - [ ] Form body parsing for POST
- [ ] auto-serve index.sh for subdirectories (`/users` -> `/users/index.sh` if dir) - [ ] auto-serve index.sh for subdirectories (`/users` -> `/users/index.sh` if dir)
- [ ] Layouts - [x] Layouts
- [ ] Caching - [ ] Caching

View File

@ -21,20 +21,35 @@ export function startWeb(rootPath: string) {
app.on(['GET', 'POST'], ['/', '/:page{.+}'], async (c) => { app.on(['GET', 'POST'], ['/', '/:page{.+}'], async (c) => {
const page = c.req.param('page') || 'index' const page = c.req.param('page') || 'index'
const params = c.req.query() if (page === 'layout') return c.text('404 Not Found', 404)
const params = c.req.query()
const path = join(root, `${page}.sh`) const path = join(root, `${page}.sh`)
const file = Bun.file(path) const file = Bun.file(path)
const layoutPath = join(root, `layout.sh`)
const layoutFile = Bun.file(layoutPath)
let layoutCode = await layoutFile.exists() ? await layoutFile.text() : ''
if (await file.exists()) { if (await file.exists()) {
let content = ''
try { try {
return c.html(await wrapAndRunCode(await file.text(), { params })) content = await wrapAndRunCode(await file.text(), { params })
} catch (e) { } catch (err) {
let error = e instanceof Error ? e.message : String(e) return c.html(shrimpError(path, err), 500)
const ansiUp = new AnsiUp()
const errorHtml = ansiUp.ansi_to_html(error)
const blue = '#42A5F5'
return c.html(`<h1 style='color:${blue}'>🫧 Error in <a href='vscode://file/${path}' style='text-decoration:none;border-bottom:1px dotted ${blue};color:${blue}'>${path}</a></h1><pre>${errorHtml}</pre>`)
} }
if (layoutCode) {
try {
return c.html(await wrapAndRunCode(layoutCode, { params, content }))
} catch (err) {
return c.html(shrimpError(layoutPath, err), 500)
}
} else {
return c.html(content)
}
} else { } else {
return c.text('404 Not Found', 404) return c.text('404 Not Found', 404)
} }
@ -46,3 +61,10 @@ export function startWeb(rootPath: string) {
port: 3000, port: 3000,
}) })
} }
function shrimpError(path: string, error: any): string {
const ansiUp = new AnsiUp()
const errorHtml = ansiUp.ansi_to_html(error?.message ?? String(error))
const blue = '#42A5F5'
return `<h1 style='color:${blue}'>🫧 Error in <a href='vscode://file/${path}' style='text-decoration:none;border-bottom:1px dotted ${blue};color:${blue}'>${path}</a></h1><pre>${errorHtml}</pre>`
}