initial port of the UI kit
This commit is contained in:
94
go/webui/icons.go
Normal file
94
go/webui/icons.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package webui
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"kjol/vdom"
|
||||
)
|
||||
|
||||
// Port of web/kit/Icons.tsx. The TSX resolves FontAwesome glyphs from an
|
||||
// app-generated registry (@appgen/faIcons). Here the registry is a package var
|
||||
// seeded with a small common set; apps add their own with RegisterIcon. Each
|
||||
// entry is the inner SVG markup for a 0 0 24 24 viewBox (Heroicons-style), so
|
||||
// the outer <svg> just sizes it.
|
||||
type iconDef struct {
|
||||
viewBox string
|
||||
content string
|
||||
}
|
||||
|
||||
var iconRegistry = map[string]iconDef{}
|
||||
|
||||
// RegisterIcon registers (or overrides) an icon. viewBox is like "0 0 24 24";
|
||||
// content is the inner SVG markup (e.g. one or more <path> elements).
|
||||
func RegisterIcon(name, viewBox, content string) {
|
||||
iconRegistry[name] = iconDef{viewBox: viewBox, content: content}
|
||||
}
|
||||
|
||||
// Icon renders a named icon at the given pixel size (0 => 16). Extra classes are
|
||||
// appended. Unknown names render an empty, correctly-sized box (never blanks the
|
||||
// layout). Mirrors Icons.tsx's <svg fill=currentColor width height>innerHTML</svg>.
|
||||
func Icon(name string, size int, class string) *vdom.VNode {
|
||||
if size <= 0 {
|
||||
size = 16
|
||||
}
|
||||
def, ok := iconRegistry[name]
|
||||
vb := "0 0 24 24"
|
||||
content := ""
|
||||
if ok {
|
||||
vb = def.viewBox
|
||||
content = def.content
|
||||
}
|
||||
s := strconv.Itoa(size)
|
||||
return vdom.El("svg",
|
||||
vdom.Attr("xmlns", "http://www.w3.org/2000/svg"),
|
||||
vdom.Attr("viewBox", vb),
|
||||
vdom.Attr("fill", "currentColor"),
|
||||
vdom.Attr("width", s), vdom.Attr("height", s),
|
||||
vdom.Attr("aria-hidden", "true"),
|
||||
vdom.Attr("class", cx("shrink-0", class)),
|
||||
vdom.Raw(content),
|
||||
)
|
||||
}
|
||||
|
||||
// IconInline is Icon with inline-block alignment (for use within text runs).
|
||||
func IconInline(name string, size int, class string) *vdom.VNode {
|
||||
return Icon(name, size, cx("inline-block align-middle", class))
|
||||
}
|
||||
|
||||
// IconSuccess / IconError are green/red inline convenience wrappers.
|
||||
func IconSuccess(name string, size int, class string) *vdom.VNode {
|
||||
return Icon(name, size, cx("inline-block align-middle text-green-600", class))
|
||||
}
|
||||
func IconError(name string, size int, class string) *vdom.VNode {
|
||||
return Icon(name, size, cx("inline-block align-middle text-red-600", class))
|
||||
}
|
||||
|
||||
// IconContainer is a flex row that vertically centers an icon + text.
|
||||
func IconContainer(children ...*vdom.VNode) *vdom.VNode {
|
||||
return vdom.El("span", kids([]vdom.Mod{vdom.Attr("class", "flex flex-row items-center gap-2")}, children)...)
|
||||
}
|
||||
|
||||
// A small default set of stroke-based icons (Heroicons outline, 24x24) so common
|
||||
// components render out of the box. Apps register more via RegisterIcon.
|
||||
func strokePath(d string) string {
|
||||
return `<path stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none" d="` + d + `"/>`
|
||||
}
|
||||
|
||||
func init() {
|
||||
reg := func(name, d string) { RegisterIcon(name, "0 0 24 24", strokePath(d)) }
|
||||
reg("chevron-left", "M15.75 19.5 8.25 12l7.5-7.5")
|
||||
reg("chevron-right", "m8.25 4.5 7.5 7.5-7.5 7.5")
|
||||
reg("chevron-down", "m19.5 8.25-7.5 7.5-7.5-7.5")
|
||||
reg("chevron-up", "m4.5 15.75 7.5-7.5 7.5 7.5")
|
||||
reg("check", "m4.5 12.75 6 6 9-13.5")
|
||||
reg("xmark", "M6 18 18 6M6 6l12 12")
|
||||
reg("x", "M6 18 18 6M6 6l12 12")
|
||||
reg("plus", "M12 4.5v15m7.5-7.5h-15")
|
||||
reg("minus", "M4.5 12h15")
|
||||
reg("bars", "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5")
|
||||
reg("arrow-right", "M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3")
|
||||
reg("external-link", "M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25")
|
||||
reg("info", "M11.25 11.25h1.5v4.5M12 8.25h.008M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z")
|
||||
reg("triangle-exclamation", "M12 9v3.75m0 3.75h.008M10.34 3.94 1.7 18a1.5 1.5 0 0 0 1.3 2.25h18a1.5 1.5 0 0 0 1.3-2.25L13.66 3.94a1.5 1.5 0 0 0-2.6 0Z")
|
||||
reg("circle-check", "M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z")
|
||||
}
|
||||
Reference in New Issue
Block a user