feat: port el-ui vessels — rename crates→vessels, add El source + manifests

This commit is contained in:
Will Anderson
2026-05-05 04:19:22 -05:00
parent b580a63540
commit faee6fdb25
145 changed files with 4050 additions and 12 deletions
+222
View File
@@ -0,0 +1,222 @@
// el-html Atomic HTML element primitives.
//
// Usage:
// el_div("class=\"card\"", inner_html)
// el_h1("", "Hello world")
// el_img("/logo.png", "Logo", "width=\"120\"")
//
// Children args are raw HTML pre-escaped by caller.
// Use el_text(s) to safely insert plain text.
// Text escaping
fn el_escape(s: String) -> String {
let s = str_replace(s, "&", "&")
let s = str_replace(s, "<", "&lt;")
let s = str_replace(s, ">", "&gt;")
let s = str_replace(s, "\"", "&quot;")
str_replace(s, "'", "&#39;")
}
fn el_text(s: String) -> String {
el_escape(s)
}
fn el_attr(name: String, value: String) -> String {
" " + name + "=\"" + el_escape(value) + "\""
}
// Block elements
fn el_div(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<div>" + children + "</div>" }
"<div " + attrs + ">" + children + "</div>"
}
fn el_section(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<section>" + children + "</section>" }
"<section " + attrs + ">" + children + "</section>"
}
fn el_article(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<article>" + children + "</article>" }
"<article " + attrs + ">" + children + "</article>"
}
fn el_header(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<header>" + children + "</header>" }
"<header " + attrs + ">" + children + "</header>"
}
fn el_footer(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<footer>" + children + "</footer>" }
"<footer " + attrs + ">" + children + "</footer>"
}
fn el_main(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<main>" + children + "</main>" }
"<main " + attrs + ">" + children + "</main>"
}
fn el_nav(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<nav>" + children + "</nav>" }
"<nav " + attrs + ">" + children + "</nav>"
}
fn el_aside(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<aside>" + children + "</aside>" }
"<aside " + attrs + ">" + children + "</aside>"
}
fn el_ul(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<ul>" + children + "</ul>" }
"<ul " + attrs + ">" + children + "</ul>"
}
fn el_ol(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<ol>" + children + "</ol>" }
"<ol " + attrs + ">" + children + "</ol>"
}
fn el_li(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<li>" + children + "</li>" }
"<li " + attrs + ">" + children + "</li>"
}
fn el_p(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<p>" + children + "</p>" }
"<p " + attrs + ">" + children + "</p>"
}
fn el_span(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<span>" + children + "</span>" }
"<span " + attrs + ">" + children + "</span>"
}
fn el_form(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<form>" + children + "</form>" }
"<form " + attrs + ">" + children + "</form>"
}
// Headings
fn el_h1(attrs: String, text: String) -> String {
if str_eq(attrs, "") { return "<h1>" + el_escape(text) + "</h1>" }
"<h1 " + attrs + ">" + el_escape(text) + "</h1>"
}
fn el_h2(attrs: String, text: String) -> String {
if str_eq(attrs, "") { return "<h2>" + el_escape(text) + "</h2>" }
"<h2 " + attrs + ">" + el_escape(text) + "</h2>"
}
fn el_h3(attrs: String, text: String) -> String {
if str_eq(attrs, "") { return "<h3>" + el_escape(text) + "</h3>" }
"<h3 " + attrs + ">" + el_escape(text) + "</h3>"
}
fn el_h4(attrs: String, text: String) -> String {
if str_eq(attrs, "") { return "<h4>" + el_escape(text) + "</h4>" }
"<h4 " + attrs + ">" + el_escape(text) + "</h4>"
}
// Interactive
fn el_button(attrs: String, label: String) -> String {
if str_eq(attrs, "") { return "<button type=\"button\">" + el_escape(label) + "</button>" }
"<button type=\"button\" " + attrs + ">" + el_escape(label) + "</button>"
}
fn el_a(href: String, attrs: String, children: String) -> String {
let h: String = "href=\"" + el_escape(href) + "\""
if str_eq(attrs, "") { return "<a " + h + ">" + children + "</a>" }
"<a " + h + " " + attrs + ">" + children + "</a>"
}
fn el_input(type_attr: String, attrs: String) -> String {
if str_eq(attrs, "") { return "<input type=\"" + type_attr + "\" />" }
"<input type=\"" + type_attr + "\" " + attrs + " />"
}
fn el_textarea(attrs: String, value: String) -> String {
if str_eq(attrs, "") { return "<textarea>" + el_escape(value) + "</textarea>" }
"<textarea " + attrs + ">" + el_escape(value) + "</textarea>"
}
fn el_label(for_id: String, attrs: String, children: String) -> String {
let f: String = "for=\"" + el_escape(for_id) + "\""
if str_eq(attrs, "") { return "<label " + f + ">" + children + "</label>" }
"<label " + f + " " + attrs + ">" + children + "</label>"
}
// Media
fn el_img(src: String, alt: String, attrs: String) -> String {
let base: String = "src=\"" + el_escape(src) + "\" alt=\"" + el_escape(alt) + "\""
if str_eq(attrs, "") { return "<img " + base + " />" }
"<img " + base + " " + attrs + " />"
}
fn el_video(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<video>" + children + "</video>" }
"<video " + attrs + ">" + children + "</video>"
}
// Inline semantic
fn el_strong(children: String) -> String {
"<strong>" + children + "</strong>"
}
fn el_em(children: String) -> String {
"<em>" + children + "</em>"
}
fn el_code(children: String) -> String {
"<code>" + children + "</code>"
}
fn el_pre(attrs: String, children: String) -> String {
if str_eq(attrs, "") { return "<pre>" + children + "</pre>" }
"<pre " + attrs + ">" + children + "</pre>"
}
fn el_hr() -> String { "<hr />" }
fn el_br() -> String { "<br />" }
// Document shell
fn el_html_doc(lang: String, head_html: String, body_html: String) -> String {
"<!doctype html><html lang=\"" + el_escape(lang) + "\"><head>"
+ head_html + "</head><body>" + body_html + "</body></html>"
}
fn el_meta(name: String, content: String) -> String {
"<meta name=\"" + el_escape(name) + "\" content=\"" + el_escape(content) + "\" />"
}
fn el_meta_charset(charset: String) -> String {
"<meta charset=\"" + el_escape(charset) + "\" />"
}
fn el_link_stylesheet(href: String) -> String {
"<link rel=\"stylesheet\" href=\"" + el_escape(href) + "\" />"
}
fn el_script_src(src: String, defer_load: Bool) -> String {
if defer_load { return "<script src=\"" + el_escape(src) + "\" defer></script>" }
"<script src=\"" + el_escape(src) + "\"></script>"
}
fn el_script_inline(js: String) -> String {
"<script>" + js + "</script>"
}
fn el_title(text: String) -> String {
"<title>" + el_escape(text) + "</title>"
}
// Entry smoke test
let sample: String = el_div("class=\"card\"", el_h2("", "Hello") + el_p("", "World"))
println("[el-html] sample = " + sample)