diff --git a/.air.toml b/.air.toml index 58fff2a..8a840b4 100644 --- a/.air.toml +++ b/.air.toml @@ -7,7 +7,7 @@ tmp_dir = "tmp" bin = "./tmp/main" cmd = "go build -o ./tmp/main ." delay = 1000 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules", "js"] exclude_file = [] exclude_regex = ["_test.go"] exclude_unchanged = false diff --git a/h/tag.go b/h/tag.go index f8bacb7..9b4b50f 100644 --- a/h/tag.go +++ b/h/tag.go @@ -453,6 +453,10 @@ func IfElseLazy(condition bool, cb1 func() Renderable, cb2 func() Renderable) Re } } +func GetTriggerName(ctx *fiber.Ctx) string { + return ctx.Get("HX-Trigger-Name") +} + func IfHtmxRequest(ctx *fiber.Ctx, node Renderable) Renderable { if ctx.Get("HX-Request") != "" { return node diff --git a/js/extensions/triggerchildren.ts b/js/extensions/trigger-children.ts similarity index 100% rename from js/extensions/triggerchildren.ts rename to js/extensions/trigger-children.ts diff --git a/js/mhtml.ts b/js/mhtml.ts index 054bef2..81d92af 100644 --- a/js/mhtml.ts +++ b/js/mhtml.ts @@ -1,6 +1,6 @@ import * as htmx from "htmx.org"; import "./extensions/pathdeps"; -import "./extensions/triggerchildren"; +import "./extensions/trigger-children"; import "./extensions/debug"; declare module "htmx.org" { diff --git a/justfile b/justfile index 8c1ea1b..a984421 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,6 @@ # Command to run and watch the Go application using Air run-app: - air + just run-gen && air & just watch-js & just watch-gen run-gen: go run ./tooling/astgen diff --git a/main.go b/main.go index 5584e17..bbb9390 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import ( "log" "mhtml/h" "mhtml/pages" - "mhtml/partials" + "mhtml/partials/load" "time" ) @@ -40,7 +40,7 @@ func main() { return err }) - partials.RegisterPartials(f) + load.RegisterPartials(f) pages.RegisterPages(f) h.Start(f, h.App{ diff --git a/partials/generated.go b/partials/load/generated.go similarity index 78% rename from partials/generated.go rename to partials/load/generated.go index 9627b4a..cfdfe1a 100644 --- a/partials/generated.go +++ b/partials/load/generated.go @@ -1,18 +1,19 @@ // Package partials THIS FILE IS GENERATED. DO NOT EDIT. -package partials +package load import "mhtml/h" import "github.com/gofiber/fiber/v2" +import "mhtml/partials" import "mhtml/partials/patient" import "mhtml/partials/sheet" func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial { path := ctx.Path() if path == "NewsSheet" || path == "/mhtml/partials.NewsSheet" { - return NewsSheet(ctx) + return partials.NewsSheet(ctx) } if path == "NewsSheetOpenCount" || path == "/mhtml/partials.NewsSheetOpenCount" { - return NewsSheetOpenCount(ctx) + return partials.NewsSheetOpenCount(ctx) } if path == "Create" || path == "/mhtml/partials/patient.Create" { return patient.Create(ctx) @@ -23,6 +24,9 @@ func GetPartialFromContext(ctx *fiber.Ctx) *h.Partial { if path == "AddPatientSheetPartial" || path == "/mhtml/partials/patient.AddPatientSheetPartial" { return patient.AddPatientSheetPartial(ctx) } + if path == "ValidateForm" || path == "/mhtml/partials/patient.ValidateForm" { + return patient.ValidateForm(ctx) + } if path == "Close" || path == "/mhtml/partials/sheet.Close" { return sheet.Close(ctx) } diff --git a/partials/base.go b/partials/load/register.go similarity index 94% rename from partials/base.go rename to partials/load/register.go index 5adc860..dbef714 100644 --- a/partials/base.go +++ b/partials/load/register.go @@ -1,4 +1,4 @@ -package partials +package load import ( "github.com/gofiber/fiber/v2" diff --git a/partials/patient/patient.go b/partials/patient/patient.go index 4511a60..e87c42c 100644 --- a/partials/patient/patient.go +++ b/partials/patient/patient.go @@ -6,6 +6,7 @@ import ( "mhtml/h" "mhtml/partials/sheet" "mhtml/ui" + "strings" "time" ) @@ -64,21 +65,48 @@ func AddPatientSheet(onClosePath string) h.Renderable { }) } +func ValidateForm(ctx *fiber.Ctx) *h.Partial { + trigger := h.GetTriggerName(ctx) + value := ctx.FormValue(trigger) + + if trigger == "name" { + if strings.ToLower(value) == "sydne" { + return h.NewPartial(h.P("that name is reserved")) + } + } + + if trigger == "reason-for-visit" { + if strings.ToLower(value) == "arm hurts" { + return h.NewPartial(h.P("lol that reason is fake")) + } + } + + if trigger == "location-name" { + if strings.ToLower(value) == "hospital" { + return h.NewPartial(h.P("that location is reserved")) + } + } + + return h.NewPartial(h.Fragment()) +} + func addPatientForm() h.Renderable { return h.Form( h.TriggerChildren(), h.Post(h.GetPartialPath(Create)), h.Class("flex flex-col gap-2"), ui.Input(ui.InputProps{ - Type: "text", - Label: "Name", - Name: "name", - DefaultValue: "fart", + Type: "text", + Label: "Name", + Name: "name", + DefaultValue: "", + ValidationPath: h.GetPartialPath(ValidateForm), }), ui.Input(ui.InputProps{ - Type: "text", - Label: "Reason for visit", - Name: "reason-for-visit", + Type: "text", + Label: "Reason for visit", + Name: "reason-for-visit", + ValidationPath: h.GetPartialPath(ValidateForm), }), ui.Input(ui.InputProps{ Type: "date", @@ -86,9 +114,10 @@ func addPatientForm() h.Renderable { Name: "appointment-date", }), ui.Input(ui.InputProps{ - Type: "text", - Label: "Location Name", - Name: "location-name", + Type: "text", + Label: "Location Name", + Name: "location-name", + ValidationPath: h.GetPartialPath(ValidateForm), }), ui.PrimaryButton(ui.ButtonProps{ Text: "Add Patient", diff --git a/tooling/astgen/entry.go b/tooling/astgen/entry.go index 3aefc18..844816c 100644 --- a/tooling/astgen/entry.go +++ b/tooling/astgen/entry.go @@ -195,11 +195,6 @@ func buildGetPartialFromContext(builder *CodeBuilder, partials []Partial) { caller := fmt.Sprintf("%s.%s", f.Package, f.FuncName) path := fmt.Sprintf("/mhtml/%s.%s", f.Import, f.FuncName) - if f.Package == "partials" { - caller = f.FuncName - path = fmt.Sprintf("/mhtml/partials.%s", f.FuncName) - } - body += fmt.Sprintf(` if path == "%s" || path == "%s" { return %s(ctx) @@ -234,19 +229,21 @@ func writePartialsFile() { builder := NewCodeBuilder(nil) builder.AppendLine(`// Package partials THIS FILE IS GENERATED. DO NOT EDIT.`) - builder.AppendLine("package partials") + builder.AppendLine("package load") builder.AddImport("mhtml/h") builder.AddImport("github.com/gofiber/fiber/v2") for _, partial := range partials { - if partial.Import != "partials" { - builder.AddImport(fmt.Sprintf(`mhtml/%s`, partial.Import)) + if partial.Import == "partials/load" { + continue } + fmt.Println(partial.Import) + builder.AddImport(fmt.Sprintf(`mhtml/%s`, partial.Import)) } buildGetPartialFromContext(builder, partials) - WriteFile(filepath.Join("partials", "generated.go"), func(content *ast.File) string { + WriteFile(filepath.Join("partials", "load", "generated.go"), func(content *ast.File) string { return builder.String() }) } diff --git a/tooling/astgen/writer.go b/tooling/astgen/writer.go index 2e758f2..b20e076 100644 --- a/tooling/astgen/writer.go +++ b/tooling/astgen/writer.go @@ -43,7 +43,7 @@ func WriteFile(path string, cb func(content *ast.File) string) { } bytes = []byte(cb(f)) - formatEnabled := false + formatEnabled := true if formatEnabled { bytes, err = format.Source(bytes) diff --git a/ui/input.go b/ui/input.go index 7364ced..fe127f9 100644 --- a/ui/input.go +++ b/ui/input.go @@ -3,27 +3,40 @@ package ui import "mhtml/h" type InputProps struct { - Id string - Label string - Name string - Type string - DefaultValue string + Id string + Label string + Name string + Type string + DefaultValue string + ValidationPath string + Childen []h.Renderable } func Input(props InputProps) h.Renderable { + + validation := h.If(props.ValidationPath != "", h.Children( + h.Post(props.ValidationPath), + h.Trigger("change"), + h.Attribute("hx-swap", "innerHTML transition:true"), + h.Attribute("hx-target", "next div"), + )) + input := h.Input( props.Type, h.Class("border p-2 rounded"), h.If(props.Id != "", h.Id(props.Id)), h.If(props.Name != "", h.Name(props.Name)), + h.If(props.Childen != nil, h.Children(props.Childen...)), h.If(props.DefaultValue != "", h.Attribute("value", props.DefaultValue)), + validation, ) - if props.Label != "" { - return h.Div( - h.Class("flex flex-col gap-1"), - h.Label(props.Label), - input, - ) - } - return input + + wrapped := h.Div( + h.Class("flex flex-col gap-1"), + h.If(props.Label != "", h.Label(props.Label)), + input, + h.Div(h.Class("text-red-500")), + ) + + return wrapped }