add magical style tags

This commit is contained in:
Chris Wanstrath 2025-11-05 16:01:19 -08:00
parent 260e2c7480
commit 4ff6368a8c
2 changed files with 31 additions and 13 deletions

View File

@ -18,8 +18,10 @@
- [x] Serve static files in pub/ - [x] Serve static files in pub/
- [x] Working CLI - [x] Working CLI
- [x] Nice error messages - [x] Nice error messages
- [ ] dev mode / prod mode (caching, errors) - [x] attrs vs styles (h1 color=blue -> style="color:blue")
- [ ] Form body parsing for POST - [x] GET params (`params.whatever`)
- [ ] auto-serve index.sh for subdirectories (`/users` -> `/users/index.sh` if dir) - [x] POST params (`params.whatever`)
- [x] Layouts - [x] Layouts
- [ ] dev mode / prod mode (caching, errors)
- [ ] auto-serve index.sh for subdirectories (`/users` -> `/users/index.sh` if dir)
- [ ] Caching - [ ] Caching

View File

@ -4,9 +4,9 @@ import { AnsiUp } from 'ansi_up'
const buffer: string[] = [] const buffer: string[] = []
const NOSPACE_TOKEN = '!!ribbit-nospace!!' const NOSPACE_TOKEN = '!!ribbit-nospace!!'
const TAG_TOKEN = '!!ribbit-tag!!' const TAG_TOKEN = '!!ribbit-tag!!'
const SELF_CLOSING = await Bun.file('./data/self-closing.json').json() const SELF_CLOSING = new Set(await Bun.file('./data/self-closing.json').json())
const HTML5_TAGS = await Bun.file('./data/tags.json').json() const HTML5_TAGS = await Bun.file('./data/tags.json').json()
const HTML5_ATTRS = await Bun.file('./data/attrs.json').json() const HTML5_ATTRS = new Set(await Bun.file('./data/attrs.json').json())
export function wrapCode(code: string): string { export function wrapCode(code: string): string {
return "ribbit do:\n " + code + "\nend" return "ribbit do:\n " + code + "\nend"
@ -55,10 +55,10 @@ const tag = async (tagName: string, atNamed = {}, ...args: any[]) => {
} }
const tagBlock = async (tagName: string, props = {}, fn: Function) => { const tagBlock = async (tagName: string, props = {}, fn: Function) => {
const attrs = Object.entries(props).map(([key, value]) => `${key}="${value}"`) const attrs = propsToAttrs(tagName, props)
const space = attrs.length ? ' ' : '' const space = attrs.length ? ' ' : ''
buffer.push(`<${tagName}${space}${attrs.join(' ')}>`) buffer.push(`<${tagName}${space}${attrs}>`)
await fn() await fn()
buffer.push(`</${tagName}>`) buffer.push(`</${tagName}>`)
} }
@ -66,9 +66,7 @@ const tagBlock = async (tagName: string, props = {}, fn: Function) => {
const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => { const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
args = args.map(arg => typeof arg === 'function' ? arg.tagName : arg) args = args.map(arg => typeof arg === 'function' ? arg.tagName : arg)
const attrs = Object.entries(atNamed) const attrs = propsToAttrs(tagName, atNamed)
.filter(([key, value]) => value)
.map(([key, value]) => `${key}="${typeof value === 'function' ? (value as any).tagName : value}"`)
const space = attrs.length ? ' ' : '' const space = attrs.length ? ' ' : ''
const children = args const children = args
.reverse() .reverse()
@ -76,8 +74,26 @@ const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
.reverse().join(' ') .reverse().join(' ')
.replaceAll(` ${NOSPACE_TOKEN} `, '') .replaceAll(` ${NOSPACE_TOKEN} `, '')
if (SELF_CLOSING.includes(tagName)) if (SELF_CLOSING.has(tagName))
buffer.push(`<${tagName}${space}${attrs.join(' ')} />`) buffer.push(`<${tagName}${space}${attrs} />`)
else else
buffer.push(`<${tagName}${space}${attrs.join(' ')}>${children}</${tagName}>`) buffer.push(`<${tagName}${space}${attrs}>${children}</${tagName}>`)
}
const propsToAttrs = (tagName: string, props: Record<string, any>): string => {
let attrs = []
let styles = []
for (const [key, value] of Object.entries(props).filter(([_, value]) => value)) {
if (HTML5_ATTRS.has(key) || HTML5_TAGS[tagName].includes(key)) {
attrs.push(`${key}="${typeof value === 'function' ? (value as any).tagName : value}"`)
} else {
styles.push(`${key}: ${value}`)
}
}
if (styles.length)
attrs.push(`style="${styles.join('; ')}"`)
return attrs.join(' ')
} }