'MiniHtml Helper
'Version: 3.31
	Type AlertInfo (Message As String, Status As String)
	Type ToastInfo (Entity As String, Action As String, Message As String, Status As String)
End Sub

Public Sub CreateTag (Name As String) As MiniHtml
	Dim tag1 As MiniHtml
	tag1.Initialize(Name)
	Return tag1
End Sub

Public Sub CreateMiniJs As MiniJs
	Dim s As MiniJs
	s.Initialize
	Return s
End Sub

Public Sub ConvertFromBytes (Buffer() As Byte) As MiniHtml
	Dim s As String = BytesToString(Buffer, 0, Buffer.Length, "UTF-8")
	Return CreateTag("").Parse(s)
End Sub

Public Sub ConvertToBytes (tag As MiniHtml) As Byte()
	Return tag.build.GetBytes("UTF8")
End Sub

Public Sub Anchor As MiniHtml
	Return CreateTag("a")
End Sub

Public Sub Button As MiniHtml
	Return CreateTag("button")
End Sub

Public Sub Div As MiniHtml
	Return CreateTag("div")
End Sub

Public Sub Span As MiniHtml
	Return CreateTag("span")
End Sub

Public Sub Strong As MiniHtml
	Return CreateTag("strong")
End Sub

Public Sub Br As MiniHtml
	Return CreateTag("br")
End Sub

Public Sub Nav As MiniHtml
	Return CreateTag("nav")
End Sub

Public Sub Form As MiniHtml
	Return CreateTag("form")
End Sub

Public Sub H1 As MiniHtml
	Return CreateTag("h1")
End Sub

Public Sub H2 As MiniHtml
	Return CreateTag("h2")
End Sub

Public Sub H3 As MiniHtml
	Return CreateTag("h3")
End Sub

Public Sub H5 As MiniHtml
	Return CreateTag("h5")
End Sub

Public Sub H6 As MiniHtml
	Return CreateTag("h6")
End Sub

Public Sub P As MiniHtml
	Return CreateTag("p")
End Sub

Public Sub Html As MiniHtml
	Return CreateTag("html").lang("en")
End Sub

Public Sub Head As MiniHtml
	Return CreateTag("head")
End Sub

Public Sub Title As MiniHtml
	Return CreateTag("title")
End Sub

Public Sub Script As MiniHtml
	Return CreateTag("script")
End Sub

Public Sub Style As MiniHtml
	Return CreateTag("style")
End Sub

Public Sub Meta As MiniHtml
	Return CreateTag("meta")
End Sub

Public Sub Link As MiniHtml
	Return CreateTag("link")
End Sub

Public Sub Body As MiniHtml
	Return CreateTag("body")
End Sub

Public Sub Icon As MiniHtml
	Return CreateTag("i")
End Sub

Public Sub Img As MiniHtml
	Return CreateTag("img")
End Sub

'Alias of Img
Public Sub Image As MiniHtml
	Return Img
End Sub

Public Sub Svg As MiniHtml
	Return CreateTag("svg")
End Sub

Public Sub Path As MiniHtml
	Return CreateTag("path")
End Sub

Public Sub Input As MiniHtml
	Return CreateTag("input")
End Sub

Public Sub Label As MiniHtml
	Return CreateTag("label")
End Sub

Public Sub Caption As MiniHtml
	Return CreateTag("caption")
End Sub

Public Sub Footer As MiniHtml
	Return CreateTag("footer")
End Sub

Public Sub Table As MiniHtml
	Return CreateTag("table")
End Sub

Public Sub Tbody As MiniHtml
	Return CreateTag("tbody")
End Sub

Public Sub Td As MiniHtml
	Return CreateTag("td")
End Sub

Public Sub Th As MiniHtml
	Return CreateTag("th")
End Sub

Public Sub Thead As MiniHtml
	Return CreateTag("thead")
End Sub

Public Sub Tr As MiniHtml
	Return CreateTag("tr")
End Sub

Public Sub Ul As MiniHtml
	Return CreateTag("ul")
End Sub

Public Sub Li As MiniHtml
	Return CreateTag("li")
End Sub

Public Sub SelectTag As MiniHtml
	Return CreateTag("select")
End Sub

Public Sub Option As MiniHtml
	Return CreateTag("option")
End Sub

Public Sub Textarea As MiniHtml
	Return CreateTag("textarea")
End Sub

' ============================
'  Bootstrap Layout Helpers
' ============================
Public Sub Container As MiniHtml
	Return Div.cls("container")
End Sub

Public Sub ContainerFluid As MiniHtml
	Return Div.cls("container-fluid")
End Sub

Public Sub Row As MiniHtml
	Return Div.cls("row")
End Sub

Public Sub Col (cols As String) As MiniHtml
	Return Div.cls("col-" & cols)
End Sub

Public Sub InputText (id As String, name As String, value As String, placeholder As String) As MiniHtml
	Return Input.attr("type", "text").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "value": value, "placeholder": placeholder))
End Sub

Public Sub InputEmail (id As String, name As String, value As String, placeholder As String) As MiniHtml
	Return Input.attr("type", "email").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "value": value, "placeholder": placeholder))
End Sub

Public Sub InputPassword (id As String, name As String, placeholder As String) As MiniHtml
	Return Input.attr("type", "password").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "placeholder": placeholder))
End Sub

Public Sub InputNumber (id As String, name As String, value As String, MinValue As String, MaxValue As String, StepValue As String) As MiniHtml
	Return Input.attr("type", "number").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "value": value, "min": MinValue, "max": MaxValue, "step": StepValue))
End Sub

Public Sub InputDate (id As String, name As String, value As String) As MiniHtml
	Return Input.attr("type", "date").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "value": value))
End Sub

Public Sub InputFile (id As String, name As String, accept As String, multiple As Boolean) As MiniHtml
	Return Input.attr("type", "file").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "accept": accept)).boolIf(multiple, "multiple")
End Sub

Public Sub TextareaInput (id As String, name As String, value As String, rows As Int, placeholder As String) As MiniHtml
	Return Textarea.cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "placeholder": placeholder)).attrIf(rows > 0, "rows", rows).textIfValue(value)
End Sub

Public Sub CheckboxInput (id As String, name As String, value As String, text As String, checked As Boolean) As MiniHtml
	Dim input1 As MiniHtml = Input.attr("type", "checkbox").cls("form-check-input").attrsIfValues(CreateMap("id": id, "name": name, "value": value)).boolIf(checked, "checked")
	Dim label1 As MiniHtml = Label.cls("form-check-label").attrIfValue("for", id).textIfValue(text)
	Return Div.cls("form-check").down(input1).Parent.down(label1).Parent
End Sub

Public Sub RadioInput (name As String, id As String, value As String, text As String, checked As Boolean) As MiniHtml
	Dim input1 As MiniHtml = Input.attr("type", "radio").cls("form-check-input").attrsIfValues(CreateMap("id": id, "name": name, "value": value)).boolIf(checked, "checked")
	Dim label1 As MiniHtml = Label.cls("form-check-label").attrIfValue("for", id).textIfValue(text)
	Return Div.cls("form-check").down(input1).Parent.down(label1).Parent
End Sub

Public Sub SelectInput (id As String, name As String, options As List, selectedValue As String, prompt As String, required As Boolean) As MiniHtml
	Dim select1 As MiniHtml = SelectTag.cls("form-select").attrsIfValues(CreateMap("id": id, "name": name)).boolIf(required, "required")
	If prompt <> "" Then OptionDisabled(prompt).up(select1)
	For Each opt As Map In options
		OptionSelected(opt.Get("text"), opt.Get("value"), selectedValue <> "" And opt.Get("value") = selectedValue).up(select1)
	Next
	Return select1
End Sub

Public Sub HiddenInput (id As String, name As String, value As String) As MiniHtml
	Return Input.attr("type", "hidden").attrsIfValues(CreateMap("id": id, "name": name, "value": value))
End Sub

Public Sub RequiredLabel (text As String, forId As String) As MiniHtml
	Return Label.attrIfvalue("for", forId).text(text).down(Span).cls("text-danger").text("*").Parent
End Sub

Public Sub RequiredTextInput (id As String, name As String, value As String) As MiniHtml
	Return Input.attr("type", "text").cls("form-control").attrsIfValues(CreateMap("id": id, "name": name, "value": value)).required
End Sub

Public Sub RequiredDropdown (id As String, name As String) As MiniHtml
	Return SelectTag.cls("form-select").attrsIfValues(CreateMap("id": id, "name": name)).required
End Sub

' ============================
'  Bootstrap UI Components
' ============================

Public Sub Card As MiniHtml
	Return Div.cls("card")
End Sub

Public Sub CardHeader As MiniHtml
	Return Div.cls("card-header")
End Sub

Public Sub CardBody As MiniHtml
	Return Div.cls("card-body")
End Sub

Public Sub CardFooter As MiniHtml
	Return Div.cls("card-footer")
End Sub

Public Sub CardTitle As MiniHtml
	Return CreateTag("h5").cls("card-title")
End Sub

Public Sub CardText As MiniHtml
	Return CreateTag("p").cls("card-text")
End Sub

Public Sub Badge (text As String, cls As String) As MiniHtml
	Return Span.cls("badge " & cls).text(text)
End Sub

Public Sub ListGroup As MiniHtml
	Return CreateTag("ul").cls("list-group")
End Sub

Public Sub ListGroupItem (text As String, cls As String) As MiniHtml
	Return Li.cls("list-group-item " & cls).textIfValue(text)
End Sub

Public Sub ListGroupButton (text As String, cls As String, active As Boolean) As MiniHtml
	Return Button.cls("list-group-item list-group-item-action").clsIf(cls <> "", cls).clsIf(active, "active").text(text)
End Sub

Public Sub ProgressBar (NowPercent As Int, MinValue As Int, MaxValue As Int, cls As String, showLabel As Boolean) As MiniHtml
	Return Div.cls("progress").down(Div).cls("progress-bar").clsIf(cls <> "", cls).sty("width: " & NowPercent & "%").attr("role", "progressbar").attr("aria-valuenow", NowPercent).attr("aria-valuemin", MinValue).attr("aria-valuemax", MaxValue).textIf(showLabel, NowPercent & "%").Parent
End Sub

Public Sub Spinner (cls As String, text As String) As MiniHtml
	Dim span1 As MiniHtml = Span.cls("visually-hidden").text(text)
	Return Div.cls("spinner-border").clsIf(cls <> "", cls).attr("role", "status").down(span1).Parent
End Sub

Public Sub SpinnerGrow (cls As String, text As String) As MiniHtml
	Dim span1 As MiniHtml = Span.cls("visually-hidden").text(text)
	Return Div.cls("spinner-grow").clsIf(cls <> "", cls).attr("role", "status").down(span1).Parent
End Sub

Public Sub AlertDismissible (message As String, status As String) As MiniHtml
	Return Div.cls("alert alert-" & status & " alert-dismissible fade show").attr("role", "alert").text(message).down(Button).cls("btn-close").attr("type", "button").attr("data-bs-dismiss", "alert").Parent
End Sub

' ============================
'  HTMX Helpers
' ============================

Public Sub HxGet (href As String, target As String, swap As String, trigger As String) As MiniHtml
	Return Anchor.attr("hx-get", href).attrsIfValues(CreateMap("hx-target": target, "hx-swap": swap, "hx-trigger": trigger))
End Sub

Public Sub HxPost (href As String, target As String, swap As String) As MiniHtml
	Return Button.attr("type", "button").attr("hx-post", href).attrsIfValues(CreateMap("hx-target": target, "hx-swap": swap))
End Sub

Public Sub ContainerHxGet (id As String, href As String, trigger As String, text As String) As MiniHtml
	Return Div.attr("id", id).attr("hx-get", href).attr("hx-trigger", trigger).text(text)
End Sub

Public Sub FormHxPost (href As String, target As String) As MiniHtml
	Return FormHx("post", href, target)
End Sub

Public Sub FormHxPut (href As String, target As String) As MiniHtml
	Return FormHx("put", href, target)
End Sub

Public Sub FormHxDelete (href As String, target As String) As MiniHtml
	Return FormHx("delete", href, target)
End Sub

Public Sub FormHx (verb As String, href As String, target As String) As MiniHtml
	Return Form.attr("hx-"& verb, href).attr("hx-target", target).attr("hx-swap", "innerHTML")
End Sub

' ============================
'  Navigation Helpers
' ============================

'Navbar with "container-fluid" class div
Public Sub Navbar (cls As String) As MiniHtml
	Return Nav.cls("navbar " & cls).down(ContainerFluid).Parent
End Sub

Public Sub NavItem (text As String, href As String, active As Boolean) As MiniHtml
	Return Li.cls("nav-item").down(Anchor).attr("href", href).cls("nav-link").clsIf(active, "active").text(text).Parent
End Sub

'Navbar with "container-fluid" class div, 2 "navbar-brand" class anchors and an icon class
Public Sub NavbarExpand (cls As String, expand As String, brand_icon_cls As String, brand_text As String) As MiniHtml
	Return Nav.cls("navbar navbar-expand-" & expand).clsIf(cls <> "", cls) _
	.down(ContainerFluid) _
	.down(Anchor).cls("navbar-brand").attr("href", "#").down(Icon).cls(brand_icon_cls).Parent.Parent _
	.down(Anchor).cls("navbar-brand").attr("href", "$SERVER_URL$").text(brand_text).Parent _
	.Parent
End Sub

Public Sub NavbarToggler As MiniHtml
	Return Button.cls("navbar-toggler d-md-block d-lg-none collapsed").attr("type", "button").attr("data-bs-toggle", "collapse").attr("data-bs-target", "#navbarCollapse").sty("border: none").down(Span).cls("navbar-toggler-icon").Parent
End Sub

Public Sub NavbarCollapse As MiniHtml
	Return Div.cls("collapse navbar-collapse").attr("id", "navbarCollapse").down(Ul).cls("navbar-nav navbar-brand ms-auto mb-md-0").Parent
End Sub

' ============================
'  Utility Helpers
' ============================

Public Sub CssLink (href As String) As MiniHtml
	Return Link.attr("rel", "stylesheet").attr("href", href)
End Sub

Public Sub JsScript (src As String) As MiniHtml
	Return Script.attr("src", src)
End Sub

Public Sub ImgResponsive (src As String, alt As String, cls As String) As MiniHtml
	Return Img.attr("src", src).attr("alt", alt).cls("img-fluid " & cls)
End Sub

Public Sub PageHeading (text As String, tag As String) As MiniHtml
	Return CreateTag(tag).text(text)
End Sub

Public Sub ButtonIcon (text As String, iconCls As String, btnCls As String) As MiniHtml
	Return Button.cls(btnCls).down(Icon).cls(iconCls).Parent.text(" " & text).Parent
End Sub

Public Sub AnchorButton (text As String, href As String, cls As String) As MiniHtml
	Return Anchor.attr("href", href).cls("btn " & cls).textIfValue(text)
End Sub

Public Sub NavLinkItem (text As String, href As String, icon_cls As String, icon_title As String) As MiniHtml
	Return Li.cls("nav-item d-block d-lg-block") _
	.down(Anchor).attr("href", href).cls("nav-link float-end") _
	.down(Icon).cls(icon_cls).attr("title", icon_title) _
	.Parent.text(text).Parent
End Sub

Public Sub NavLinkItemImage (href As String, img_src As String, img_title As String) As MiniHtml
	Return Li.cls("nav-item d-block d-lg-none").multiline _
	.down(Anchor).cls("nav-link float-end").attr("href", href).attr("target", "_blank").multiline _
	.down(Img).attr("src", img_src).cls("my-1").sty("height: 36px").attrIf(img_title <> "", "title", img_title) _
	.Parent.Parent
End Sub

'(deprecated)
Public Sub AnchorIcon (cls As String, hx_get As String, title_text As String, icon_class As String) As MiniHtml
	Return Anchor.cls(cls).attr("hx-get", hx_get).attr("hx-target", "#modal-content").attr("hx-trigger", "click").attr("data-bs-target", "#modal-container").attr("data-bs-toggle", "modal").down(Icon).cls(icon_class).attr("title", title_text).Parent
End Sub

Public Sub IconAnchor (cls As String, href As String, icon_class As String, icon_title As String) As MiniHtml
	Return Anchor.cls(cls).attrIf(href <> "", "href", href).down(Icon).cls(icon_class).attrIf(icon_title <> "", "title", icon_title).Parent
End Sub

Public Sub ImageAnchor (href As String, img_src As String, img_class As String, img_title As String) As MiniHtml
	Return Anchor.attrIf(href <> "", "href", href).down(Img).attr("src", img_src).cls(img_class).attrIf(img_title <> "", "title", img_title).Parent
End Sub

Public Sub FavoriteIcon (icon_type As String, href As String) As MiniHtml
	Return Link.attr("rel", "icon").attr("type", icon_type).attr("href", href)
End Sub

Public Sub ButtonClose As MiniHtml
	Return Button.attr("type", "button").cls("btn-close").attr("data-bs-dismiss", "modal")
End Sub

Public Sub ButtonAdd (text As String, cls As String, hx_get As String, hx_target As String, hx_trigger As String, data_bs_target As String, data_bs_toggle As String) As MiniHtml
	Return Button.cls(cls).attr("hx-get", hx_get).attr("hx-target", hx_target).attr("hx-trigger", hx_trigger).attr("data-bs-target", data_bs_target).attr("data-bs-toggle", data_bs_toggle).down(Icon).cls("bi bi-plus-lg me-2").Parent.text(text)
End Sub

Public Sub ButtonSubmit (text As String, cls As String) As MiniHtml
	Return Button.attr("type", "submit").cls(cls).text(text)
End Sub

Public Sub ButtonCancel (text As String, cls As String) As MiniHtml
	Return Button.attr("type", "button").cls(cls).attr("data-bs-dismiss", "modal").text(text)
End Sub

Public Sub ButtonSearch (text As String, cls As String, hx_post As String, hx_target As String) As MiniHtml
	Return Button.cls(cls).text(text).attr("hx-post", hx_post).attr("hx-target", hx_target).attr("hx-swap", "innerHTML")
End Sub

Public Sub InputSearch (cls As String, id As String, name As String) As MiniHtml
	Return Input.attr("type", "text").cls(cls).attr("id", id).attr("name", name)
End Sub

Public Sub TextLabel (text As String, cls As String, forId As String) As MiniHtml
	Return Label.attr("for", forId).cls(cls).text(text)
End Sub

Public Sub FormGroup As MiniHtml
	Return Div.cls("form-group")
End Sub

Public Sub InputGroup As MiniHtml
	Return Div.cls("input-group mb-3")
End Sub

Public Sub ContainerModal As MiniHtml
	Return Div.attr("id", "modal-container").cls("modal fade").attr("tabindex", "-1").attr("aria-hidden", "true") _
	.down(Div.cls("modal-dialog modal-dialog-centered")) _
	.down(Div.cls("modal-content").attr("id", "modal-content")).Parent.Parent
End Sub

Public Sub ContainerToast As MiniHtml
	Return Div.cls("position-fixed end-0 p-3").sty("z-index: 2000").sty("bottom: 0%") _
	.down(Div.attr("id", "toast-container").cls("toast align-items-center text-bg-success border-0").attr("role", "alert")) _
	.down(Div.cls("d-flex")) _
	.down(Div.cls("toast-body").attr("id", "toast-body").text("Operation successful!")).Parent _
	.down(ButtonClose.cls("btn-close-white me-2 m-auto").attr("data-bs-dismiss", "toast")).Parent.Parent.Parent
End Sub

Public Sub ContainerModalWithButton (TitleText As String, ParagraphText As String, ButtonText As String) As MiniHtml
    Return Div.cls("modal-dialog modal-lg modal-dialog-centered") _
	.down(Div).cls("modal-content") _
	.down(Div).cls("modal-header") _
	.down(H5).cls("modal-title").text(TitleText).Parent.Parent _
	.down(Div).cls("modal-body") _
	.down(P).text(ParagraphText).Parent.Parent _
	.down(Div).cls("modal-footer") _
	.down(Button).attr("type", "button").cls("btn btn-secondary text-uppercase").attr("data-bs-dismiss", "modal").text(ButtonText).Parent.Parent.Parent
End Sub

Public Sub ModalHeader (text As String) As MiniHtml
	Return Div.cls("modal-header").down(H5).cls("modal-title").text(text).Parent.down(ButtonClose).Parent
End Sub

Public Sub ModalBody As MiniHtml
	Return Div.cls("modal-body")
End Sub

Public Sub ModalMessage As MiniHtml
	Return Div.attr("id", "modal-messages")
End Sub

Public Sub ModalFooter (Submit_text As String, Cancel_text As String, Submit_class As String, Cancel_class As String) As MiniHtml
	Dim div1 As MiniHtml = Div.cls("modal-footer")
	ButtonSubmit(Submit_text, "btn btn-" & Submit_class & " px-3").up(div1)
	ButtonCancel(Cancel_text, "btn btn-" & Cancel_class & " px-3").up(div1)
	Return div1
End Sub

Public Sub OptionDisabled (text As String) As MiniHtml
	Return Option.text(text).attr("value", "").disabled
End Sub

Public Sub OptionSelected (text As String, value As String, selected As Boolean) As MiniHtml
	Return Option.text(text).attr("value", value).selectedIf(selected)
End Sub

Public Sub ResponsiveHeader As MiniHtml
	Return Head _
	.down(Meta).attr("charset", "UTF-8").Parent _
	.down(Meta).attr("name", "viewport").attr("content", "width=device-width, initial-scale=1.0").Parent
End Sub

Public Sub CopyrightFooter As MiniHtml
	Return Footer.cls("footer mt-auto py-3 bg-body-tertiary border-top") _
	.down(Div).cls("footer small text-center d-md-block").sty("font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif") _
	.down(Caption).text("$APP_COPYRIGHT$") _
	.down(Br).Parent.text("Made with ") _
	.down(Span).sty("color: red") _
	.down(Icon).cls("bi bi-heart").Parent.Parent.text(" in B4X").Parent.Parent
End Sub

Public Sub SponsorLink As MiniHtml
	Return Div.cls("text-center font-weight-bold d-none d-lg-block").sty("background-color: whitesmoke").down(Anchor).attr("href", "https://paypal.me/aeric80/").attr("target", "_blank").down(Img).attr("src", "/assets/img/sponsor.png").cls("mx-2").sty("width: 174px").Parent.Parent
End Sub

Public Sub GitHubLink As MiniHtml
	Return Div.cls("text-center mb-3") _
	.down(Anchor).attr("href", "https://github.com/pyhoon").attr("aria-label", "github").attr("title", "GitHub").attr("target", "_blank") _
	.down(Svg).attr("aria-hidden", "true").attr("width", "24").attr("height", "24").attr("version", "1.1").attr("viewBox", "0 0 16 16") _
	.down(Path).attr("fill-rule", "evenodd").attr("d", "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z").Parent.Parent.Parent
End Sub

' ============================
' Custom Components
' ============================

Public Sub CreateAlertInfo (Message As String, Status As String) As AlertInfo
	Dim t1 As AlertInfo
	t1.Initialize
	t1.Message = Message
	t1.Status = Status
	Return t1
End Sub

Public Sub CreateToastInfo (Entity As String, Action As String, Message As String, Status As String) As ToastInfo
	Dim t1 As ToastInfo
	t1.Initialize
	t1.Entity = Entity
	t1.Action = Action
	t1.Message = Message
	t1.Status = Status
	Return t1
End Sub

Public Sub Alert (info As AlertInfo) As String
	Return Div.cls("alert alert-" & info.Status).text(info.Message).build
End Sub

Public Sub Toast (id As String, table1 As MiniHtml, info As ToastInfo) As String
	Return Div.attr("id", id).attr("hx-swap-oob", "true").add(table1).build & CRLF & CreateCustomEventScript(info).Generate
End Sub

Public Sub CreateCustomEventScript (info As ToastInfo) As MiniJs
	Dim s As MiniJs = CreateMiniJs
	s.AddCustomEventDispatch("entity:changed", CreateMap("entity": info.Entity, "action": info.Action, "message": info.Message, "status": info.Status))
	Return s