From c0f161abe144dd8fb98bf64116c397a57ac61a4d Mon Sep 17 00:00:00 2001 From: Eden Kirin Date: Mon, 5 Feb 2024 22:30:11 +0100 Subject: [PATCH] Initial --- .air.toml | 37 ++ .gitignore | 8 + Makefile | 16 + app/data/catbreeds.go | 679 ++++++++++++++++++++++++++++ app/handlers/about.go | 17 + app/handlers/home.go | 23 + app/handlers/interactive.go | 91 ++++ app/handlers/render.go | 16 + app/main.go | 7 + app/router/helpers.go | 1 + app/router/router.go | 80 ++++ app/templates/about.templ | 16 + app/templates/about_templ.go | 140 ++++++ app/templates/home.templ | 11 + app/templates/home_templ.go | 95 ++++ app/templates/interactive.templ | 229 ++++++++++ app/templates/interactive_templ.go | 693 +++++++++++++++++++++++++++++ app/templates/layout.templ | 45 ++ app/templates/layout_templ.go | 176 ++++++++ app/templates/types.go | 21 + app/types/catbreed.go | 9 + app/types/user.go | 6 + go.mod | 22 + go.sum | 41 ++ static/js/htmx.min.js | 1 + static/styles.css | 0 26 files changed, 2480 insertions(+) create mode 100644 .air.toml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 app/data/catbreeds.go create mode 100644 app/handlers/about.go create mode 100644 app/handlers/home.go create mode 100644 app/handlers/interactive.go create mode 100644 app/handlers/render.go create mode 100644 app/main.go create mode 100644 app/router/helpers.go create mode 100644 app/router/router.go create mode 100644 app/templates/about.templ create mode 100644 app/templates/about_templ.go create mode 100644 app/templates/home.templ create mode 100644 app/templates/home_templ.go create mode 100644 app/templates/interactive.templ create mode 100644 app/templates/interactive_templ.go create mode 100644 app/templates/layout.templ create mode 100644 app/templates/layout_templ.go create mode 100644 app/templates/types.go create mode 100644 app/types/catbreed.go create mode 100644 app/types/user.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 static/js/htmx.min.js create mode 100644 static/styles.css diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..4d35b1a --- /dev/null +++ b/.air.toml @@ -0,0 +1,37 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] +args_bin = [] +bin = "./tmp/main" +cmd = "templ generate; go build -o ./tmp/main ./app/." +delay = 1000 +exclude_dir = ["assets", "tmp", "vendor", "testdata", "build"] +exclude_file = [] +exclude_regex = ["_test.go", "_templ.go"] +exclude_unchanged = false +follow_symlink = false +full_bin = "" +include_dir = [] +include_ext = ["go", "tpl", "tmpl", "html", "templ"] +kill_delay = "0s" +log = "build-errors.log" +send_interrupt = false +stop_on_error = true + +[color] +app = "" +build = "yellow" +main = "magenta" +runner = "green" +watcher = "cyan" + +[log] +time = false + +[misc] +clean_on_exit = false + +[screen] +clear_on_rebuild = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2813fa5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.vscode +/.idea + +/build +/tmp + +/config.yaml +/.env.production diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08a7968 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +EXEC=fiber-sessions-app + + +run: + @air + +templ: + @templ generate + +.PHONY: build +build: templ + @CGO_ENABLED=0 go build -ldflags "-s -w" -o ./build/${EXEC} ./app/. + + +upgrade-packages: + @go get -u ./... diff --git a/app/data/catbreeds.go b/app/data/catbreeds.go new file mode 100644 index 0000000..2cfbb7d --- /dev/null +++ b/app/data/catbreeds.go @@ -0,0 +1,679 @@ +package data + +import "fiber-sessions/app/types" + +var CatBreeds []types.CatBreed = []types.CatBreed{ + { + Breed: "Abyssinian", + Country: "Ethiopia", + Origin: "Natural/Standard", + Coat: "Short", + Pattern: "Ticked", + }, + { + Breed: "Aegean", + Country: "Greece", + Origin: "Natural/Standard", + Coat: "Semi-long", + Pattern: "Bi- or tri-colored", + }, + { + Breed: "American Curl", + Country: "United States", + Origin: "Mutation", + Coat: "Short/Long", + Pattern: "All", + }, + { + Breed: "American Bobtail", + Country: "United States", + Origin: "Mutation", + Coat: "Short/Long", + Pattern: "All", + }, + { + Breed: "American Shorthair", + Country: "United States", + Origin: "Natural", + Coat: "Short", + Pattern: "All but colorpoint", + }, + { + Breed: "American Wirehair", + Country: "United States", + Origin: "Mutation", + Coat: "Rex", + Pattern: "All but colorpoint", + }, + + { + Breed: "Arabian Mau", + Country: "Arabian Peninsula", + Origin: "Natural", + Coat: "Short", + Pattern: "", + }, + { + Breed: "Australian Mist", + Country: "Australia", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Spotted and Classic tabby", + }, + { + Breed: "Asian", + Country: "United Kingdom", + Origin: "", + Coat: "Short", + Pattern: "Evenly solid", + }, + { + Breed: "Asian Semi-longhair", + Country: "United Kingdom", + Origin: "Crossbreed", + Coat: "Semi-long", + Pattern: "Solid", + }, + { + Breed: "Balinese", + Country: "United States", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "Colorpoint", + }, + { + Breed: "Bambino", + Country: "United States", + Origin: "Crossbreed", + Coat: "Hairless/Furry down", + Pattern: "", + }, + { + Breed: "Bengal", + Country: "United States", + Origin: "Hybrid", + Coat: "Short", + Pattern: "Spotted/Marbled", + }, + { + Breed: "Birman", + Country: "France", + Origin: "Natural", + Coat: "Semi Long", + Pattern: "Colorpoint", + }, + { + Breed: "Bombay", + Country: "United States", + Origin: "Crossbred", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Brazilian Shorthair", + Country: "Brazil", + Origin: "Natural", + Coat: "Short", + Pattern: "All", + }, + { + Breed: "British Semi-longhair", + Country: "United Kingdom", + Origin: "", + Coat: "Medium", + Pattern: "All", + }, + { + Breed: "British Shorthair", + Country: "United Kingdom", + Origin: "Natural", + Coat: "Short", + Pattern: "All", + }, + { + Breed: "British Longhair", + Country: "United Kingdom", + Origin: "", + Coat: "Long", + Pattern: "", + }, + { + Breed: "Burmese", + Country: "Burma and Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Burmilla", + Country: "United Kingdom", + Origin: "Crossbreed", + Coat: "Short/Long", + Pattern: "", + }, + { + Breed: "California Spangled", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Chantilly-Tiffany", + Country: "United States", + Origin: "", + Coat: "", + Pattern: "", + }, + { + Breed: "Chartreux", + Country: "France", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Chausie", + Country: "France", + Origin: "Hybrid", + Coat: "Short", + Pattern: "Ticked", + }, + { + Breed: "Cheetoh", + Country: "United States", + Origin: "Hybrid Crossbreed", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Cornish Rex", + Country: "United Kingdom (England)", + Origin: "Mutation", + Coat: "Rex", + Pattern: "All", + }, + { + Breed: "Cymric or Manx Longhair", + Country: "United Kingdom (Isle of Man)", + Origin: "Natural/Mutation", + Coat: "Long", + Pattern: "", + }, + { + Breed: "Cyprus", + Country: "Cyprus", + Origin: "Natural", + Coat: "All", + Pattern: "All", + }, + { + Breed: "Devon Rex", + Country: "United Kingdom (England)", + Origin: "Mutation", + Coat: "Rex", + Pattern: "All", + }, + { + Breed: "Donskoy, or Don Sphynx", + Country: "Russia", + Origin: "", + Coat: "Hairless", + Pattern: "", + }, + { + Breed: "Dragon Li", + Country: "China", + Origin: "Natural", + Coat: "Short", + Pattern: "Striped tabby", + }, + { + Breed: "Dwarf cat, or Dwelf", + Country: "", + Origin: "Crossbreed", + Coat: "", + Pattern: "Hairless", + }, + { + Breed: "Egyptian Mau", + Country: "Egypt", + Origin: "Natural", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "European Shorthair", + Country: "Finland and Sweden", + Origin: "Natural", + Coat: "Short", + Pattern: "", + }, + { + Breed: "Exotic Shorthair", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "All", + }, + { + Breed: "Foldex[4]", + Country: "Canada", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "All", + }, + { + Breed: "German Rex", + Country: "East Germany", + Origin: "Mutation", + Coat: "Rex", + Pattern: "", + }, + { + Breed: "Havana Brown", + Country: "United Kingdom", + Origin: "", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Highlander", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short/Long", + Pattern: "All", + }, + { + Breed: "Himalayan, or Colorpoint Persian", + Country: "United States/United Kingdom", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "Colorpoint", + }, + { + Breed: "Japanese Bobtail", + Country: "Japan", + Origin: "Natural", + Coat: "Short/Long", + Pattern: "All but colorpoint and ticked", + }, + { + Breed: "Javanese", + Country: "United States", + Origin: "Crossbreed", + Coat: "Long/Short", + Pattern: "Colorpoint", + }, + { + Breed: "Karelian Bobtail", + Country: "Western Russia", + Origin: "Natural", + Coat: "", + Pattern: "", + }, + { + Breed: "Khao Manee", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Korat", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Korean Bobtail", + Country: "Korea", + Origin: "Natural", + Coat: "Short/Long", + Pattern: "Colorprint", + }, + { + Breed: "Korn Ja", + Country: "Thailand", + Origin: "Natural", + Coat: "Short/Hairless", + Pattern: "Solid", + }, + { + Breed: "Kurilian Bobtail, or Kuril Islands Bobtail", + Country: "Eastern Russia,Japan", + Origin: "Natural", + Coat: "Short/Long", + Pattern: "", + }, + { + Breed: "LaPerm", + Country: "United States", + Origin: "Mutation", + Coat: "Rex", + Pattern: "All", + }, + { + Breed: "Lykoi", + Country: "United States", + Origin: "Natural/Mutation", + Coat: "Partly Hairless", + Pattern: "Ticked", + }, + { + Breed: "Maine Coon", + Country: "United States", + Origin: "Natural", + Coat: "Long", + Pattern: "All but colorpoint and ticked", + }, + { + Breed: "Manx", + Country: "United Kingdom (Isle of Man)", + Origin: "Mutation", + Coat: "Short/Long", + Pattern: "All but colorpoint", + }, + { + Breed: "Mekong Bobtail", + Country: "Russia", + Origin: "Natural/Mutation", + Coat: "Short", + Pattern: "Colorpoint", + }, + { + Breed: "Minskin", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short/Hairless", + Pattern: "All", + }, + { + Breed: "Munchkin", + Country: "United States", + Origin: "Mutation", + Coat: "", + Pattern: "", + }, + { + Breed: "Nebelung", + Country: "United States", + Origin: "", + Coat: "Semi-long", + Pattern: "Solid", + }, + { + Breed: "Napoleon", + Country: "", + Origin: "", + Coat: "Long/short", + Pattern: "Varied", + }, + { + Breed: "Norwegian Forest cat", + Country: "Norway", + Origin: "Natural", + Coat: "Long", + Pattern: "All but colorpoint", + }, + { + Breed: "Ocicat", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Ojos Azules", + Country: "United States", + Origin: "", + Coat: "", + Pattern: "", + }, + { + Breed: "Oregon Rex", + Country: "United States", + Origin: "Mutation", + Coat: "Rex", + Pattern: "", + }, + { + Breed: "Oriental Bicolor", + Country: "", + Origin: "", + Coat: "", + Pattern: "Bicolor", + }, + { + Breed: "Oriental Shorthair", + Country: "", + Origin: "", + Coat: "Short", + Pattern: "All but colorpoint", + }, + { + Breed: "Oriental Longhair", + Country: "", + Origin: "", + Coat: "Semi-long", + Pattern: "", + }, + { + Breed: "PerFoldæ(Experimental Breed - WCF)", + Country: "Europe", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "All", + }, + { + Breed: "Persian (Modern Persian Cat)", + Country: "Iran (Persia)", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "All", + }, + { + Breed: "Persian (Traditional Persian Cat)", + Country: "Greater Iran", + Origin: "Natural", + Coat: "Long", + Pattern: "All", + }, + { + Breed: "Peterbald", + Country: "Russia", + Origin: "Crossbreed", + Coat: "Hairless", + Pattern: "All", + }, + { + Breed: "Pixie-bob", + Country: "United States", + Origin: "Natural", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Raas", + Country: "Indonesia", + Origin: "Natural", + Coat: "Short", + Pattern: "", + }, + { + Breed: "Ragamuffin", + Country: "United States", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "All", + }, + { + Breed: "Ragdoll", + Country: "United States", + Origin: "Crossbreed", + Coat: "Long", + Pattern: "Colorpoint/Mitted/Bicolor", + }, + { + Breed: "Russian Blue", + Country: "Russia", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Russian White, Black and Tabby", + Country: "Australia", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "", + }, + { + Breed: "Sam Sawet", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Savannah", + Country: "United States", + Origin: "Hybrid", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Scottish Fold", + Country: "United Kingdom (Scotland)", + Origin: "Natural/Mutation", + Coat: "Short/Long", + Pattern: "All", + }, + { + Breed: "Selkirk Rex", + Country: "United States", + Origin: "Mutation/Cross", + Coat: "Rex (Short/Long)", + Pattern: "All", + }, + { + Breed: "Serengeti", + Country: "United States", + Origin: "Hybrid Crossbreed", + Coat: "Short", + Pattern: "Spotted", + }, + { + Breed: "Serrade petit", + Country: "France", + Origin: "Natural", + Coat: "Short", + Pattern: "", + }, + { + Breed: "Siamese", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Colorpoint", + }, + { + Breed: "Siberian", + Country: "Russia", + Origin: "Natural", + Coat: "Semi-long", + Pattern: "All", + }, + { + Breed: "Singapura", + Country: "Singapore", + Origin: "Natural", + Coat: "Short", + Pattern: "Ticked", + }, + { + Breed: "Snowshoe", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Colorpoint", + }, + { + Breed: "Sokoke", + Country: "Kenya", + Origin: "Natural", + Coat: "Short", + Pattern: "Classic tabby with ticking", + }, + { + Breed: "Somali", + Country: "Somalia", + Origin: "Mutation", + Coat: "Long", + Pattern: "Ticked", + }, + { + Breed: "Sphynx", + Country: "Canada", + Origin: "Mutation", + Coat: "Hairless", + Pattern: "All", + }, + { + Breed: "Suphalak", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Thai", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Colorpoint", + }, + { + Breed: "Thai Lilac", + Country: "Thailand", + Origin: "Natural", + Coat: "Short", + Pattern: "Solid", + }, + { + Breed: "Tonkinese", + Country: "Canada", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Colorpoint/Mink/Solid", + }, + { + Breed: "Toyger", + Country: "United States", + Origin: "Crossbreed", + Coat: "Short", + Pattern: "Mackerel", + }, + { + Breed: "Turkish Angora", + Country: "Turkey", + Origin: "Natural", + Coat: "Semi-long", + Pattern: "All but colorpoint", + }, + { + Breed: "Ukrainian Levkoy", + Country: "Ukraine", + Origin: "", + Coat: "Hairless", + Pattern: "", + }, + { + Breed: "York Chocolate", + Country: "United States (New York)", + Origin: "Natural", + Coat: "Long", + Pattern: "Solid", + }, +} diff --git a/app/handlers/about.go b/app/handlers/about.go new file mode 100644 index 0000000..dd1d92a --- /dev/null +++ b/app/handlers/about.go @@ -0,0 +1,17 @@ +package handlers + +import ( + "fiber-sessions/app/templates" + + "github.com/gofiber/fiber/v2" +) + +var pcAbout templates.PageContext = templates.PageContext{ + Title: "Welcome to the demo - About", + ActivePage: "about", +} + +func About(f *fiber.Ctx) error { + Render(f, templates.About(pcAbout)) + return nil +} diff --git a/app/handlers/home.go b/app/handlers/home.go new file mode 100644 index 0000000..b2fd86d --- /dev/null +++ b/app/handlers/home.go @@ -0,0 +1,23 @@ +package handlers + +import ( + "fiber-sessions/app/templates" + "fiber-sessions/app/types" + + "github.com/gofiber/fiber/v2" +) + +func Home(f *fiber.Ctx) error { + user := types.User{ + FirstName: "Pero", + LastName: "Perić", + } + + pc := templates.PageContext{ + Title: "Welcome to the demo", + ActivePage: "home", + User: &user, + } + Render(f, templates.Home(pc)) + return nil +} diff --git a/app/handlers/interactive.go b/app/handlers/interactive.go new file mode 100644 index 0000000..fa38f1d --- /dev/null +++ b/app/handlers/interactive.go @@ -0,0 +1,91 @@ +package handlers + +import ( + "fiber-sessions/app/data" + "fiber-sessions/app/templates" + "fiber-sessions/app/types" + "strconv" + "strings" + + "github.com/gofiber/fiber/v2" +) + +var pcInteractive templates.PageContext = templates.PageContext{ + Title: "Welcome to the demo - Interactive", + ActivePage: "interactive", +} + +func Interactive(f *fiber.Ctx) error { + Render(f, templates.Interactive(pcInteractive, data.CatBreeds)) + return nil +} + +func InteractiveSwapContent(f *fiber.Ctx) error { + contentIndexStr := f.Query("content") + contentIndex, err := strconv.Atoi(contentIndexStr) + if err != nil { + contentIndex = 0 + } + Render(f, templates.InteractiveSwapContent(pcInteractive, contentIndex)) + return nil +} + +func FilterCatBreeds(f *fiber.Ctx) error { + breedQuery := strings.ToLower(f.Query("breed")) + countryQuery := f.Query("country") + + var catBreeds []types.CatBreed = []types.CatBreed{} + + for _, cb := range data.CatBreeds { + appendToList := + (len(breedQuery) > 0 && + strings.Contains(strings.ToLower(cb.Breed), breedQuery) || + len(breedQuery) == 0) && + ((len(countryQuery) > 0 && + cb.Country == countryQuery) || + len(countryQuery) == 0) + + if appendToList { + catBreeds = append(catBreeds, cb) + } + } + + Render(f, templates.RenderCatBreedsTable(catBreeds)) + return nil +} + +func ValidateForm(f *fiber.Ctx) error { + content := templates.ValidateFormContent{ + Validated: true, + NumValue: f.FormValue("number-value"), + StrValue: f.FormValue("string-value"), + } + + numValue, err := strconv.Atoi(content.NumValue) + if err != nil { + content.HasNumValueError = true + content.NumValueError = "This is not valid number" + } + if !content.HasNumValueError { + if numValue < 0 { + content.HasNumValueError = true + content.NumValueError = "Value is less than 0" + } + if numValue > 100 { + content.HasNumValueError = true + content.NumValueError = "Value is greater than 100" + } + } + + if len(content.StrValue) < 5 { + content.HasStrValueError = true + content.StrValueError = "String length is less than 5" + } + if len(content.StrValue) > 10 { + content.HasStrValueError = true + content.StrValueError = "String length is more than 10" + } + + Render(f, templates.RenderInteractiveForm(content)) + return nil +} diff --git a/app/handlers/render.go b/app/handlers/render.go new file mode 100644 index 0000000..575a30e --- /dev/null +++ b/app/handlers/render.go @@ -0,0 +1,16 @@ +package handlers + +import ( + "github.com/a-h/templ" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/adaptor" +) + +// example taken from https://github.com/a-h/templ/tree/main/examples/integration-gofiber +func Render(c *fiber.Ctx, component templ.Component, options ...func(*templ.ComponentHandler)) error { + componentHandler := templ.Handler(component) + for _, o := range options { + o(componentHandler) + } + return adaptor.HTTPHandler(componentHandler)(c) +} diff --git a/app/main.go b/app/main.go new file mode 100644 index 0000000..1f6e107 --- /dev/null +++ b/app/main.go @@ -0,0 +1,7 @@ +package main + +import "fiber-sessions/app/router" + +func main() { + router.Serve() +} diff --git a/app/router/helpers.go b/app/router/helpers.go new file mode 100644 index 0000000..7ef135b --- /dev/null +++ b/app/router/helpers.go @@ -0,0 +1 @@ +package router diff --git a/app/router/router.go b/app/router/router.go new file mode 100644 index 0000000..f54f55d --- /dev/null +++ b/app/router/router.go @@ -0,0 +1,80 @@ +package router + +import ( + "fiber-sessions/app/handlers" + "fmt" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" + "github.com/gofiber/fiber/v2/middleware/logger" +) + +const ( + APPHOST string = "127.0.0.1" + APPPORT int = 8080 + STATIC_PATH string = "./static" +) + +func initApp() *fiber.App { + app := fiber.New(fiber.Config{ + CaseSensitive: true, + StrictRouting: true, + }) + return app +} + +func initCorsMiddleware(app *fiber.App) { + allowHeaders := []string{ + "Content-Type", + "Content-Length", + "Accept-Encoding", + "X-CSRF-Token", + "Authorization", + "accept", + "origin", + "Cache-Control", + "X-Requested-With", + "x-timezone", + "Access-Control-Allow-Origin", + "Access-Control-Max-Age", + } + + app.Use(cors.New(cors.Config{ + AllowOrigins: "*", + AllowHeaders: strings.Join(allowHeaders[:], ", "), + })) +} + +func initLogging(app *fiber.App) { + app.Use( + logger.New(), // add Logger middleware + ) +} + +func initRouter(app *fiber.App) { + app.Get("/", handlers.Home) + app.Get("/about", handlers.About) + + interactiveGroup := app.Group("/interactive") + { + interactiveGroup.Get("", handlers.Interactive) + interactiveGroup.Get("/swap-content", handlers.InteractiveSwapContent) + interactiveGroup.Get("/filter-cat-breeds", handlers.FilterCatBreeds) + interactiveGroup.Post("/validate-form", handlers.ValidateForm) + } + + app.Static("/static", STATIC_PATH) +} + +func Serve() { + serverAddr := fmt.Sprintf("%s:%d", APPHOST, APPPORT) + fmt.Printf("Starting serving on http://%s\n", serverAddr) + + app := initApp() + initLogging(app) + initCorsMiddleware(app) + initRouter(app) + + app.Listen(serverAddr) +} diff --git a/app/templates/about.templ b/app/templates/about.templ new file mode 100644 index 0000000..9258d3d --- /dev/null +++ b/app/templates/about.templ @@ -0,0 +1,16 @@ +package templates + +templ About(pc PageContext) { + @baseLayout(pc) { +

Bacon ipsum dolor amet cow capicola pancetta picanha biltong brisket filet mignon turducken beef ribs burgdoggen landjaeger meatball venison shank. Capicola ham pork chop, biltong kielbasa pancetta short loin jowl cupim pig jerky drumstick turducken burgdoggen beef. Spare ribs flank ribeye cow doner, shank chuck bacon ham hock porchetta kielbasa tri-tip. Ham t-bone chislic, capicola andouille ham hock frankfurter tri-tip sausage kevin landjaeger shank ribeye. Swine tri-tip spare ribs, rump flank bresaola kevin tail. Meatball tail picanha cow, frankfurter ribeye sirloin pork belly short loin pig. Filet mignon spare ribs pastrami, tri-tip ball tip tongue fatback pork chop.

+

Cupim biltong salami meatball ball tip buffalo, shoulder tenderloin beef ribs porchetta tail boudin chislic. Pastrami short ribs bresaola spare ribs, ham landjaeger brisket flank buffalo sirloin meatloaf tail chislic kielbasa. Leberkas t-bone hamburger pastrami, tri-tip tenderloin spare ribs alcatra filet mignon swine. Pork chop meatball buffalo alcatra cow beef, spare ribs pork loin pork ball tip corned beef sirloin pork belly fatback ham hock. Meatball ham hock filet mignon frankfurter, burgdoggen swine shankle pork belly chuck buffalo andouille corned beef pastrami turkey. Andouille short loin capicola tail pork belly biltong.

+

Frankfurter t-bone hamburger meatball tongue capicola. Sausage beef ribs pig, landjaeger salami kielbasa shank cow strip steak doner brisket drumstick sirloin. Ground round ham pork belly pig tri-tip, pastrami ham hock. Bacon shankle brisket rump pork loin drumstick. Chicken shankle picanha corned beef sirloin. Venison kevin jerky ham kielbasa. Prosciutto pork chop brisket pork belly.

+

Landjaeger tenderloin t-bone turkey buffalo, turducken beef ribs ham hock chuck frankfurter strip steak. Chuck frankfurter jowl jerky tri-tip bacon cow ribeye buffalo capicola bresaola drumstick beef ribs pork belly. Pig brisket tail prosciutto cupim andouille. Venison ground round kielbasa prosciutto jerky spare ribs. Meatball sirloin jerky, turducken tri-tip kevin brisket pork chop sausage rump. Ball tip pork loin frankfurter pig, capicola prosciutto tail bacon short ribs. Chislic porchetta meatloaf, picanha spare ribs kielbasa beef kevin capicola pork loin.

+

Tenderloin corned beef prosciutto fatback salami porchetta capicola meatball chuck jowl pork loin shoulder short ribs. Ham hock doner biltong, salami cow jerky bresaola drumstick short loin shankle chuck andouille ground round buffalo. Shankle pork belly landjaeger, corned beef hamburger sausage sirloin swine filet mignon short loin kevin. Jowl picanha pork chop meatball salami corned beef kielbasa. Ribeye leberkas bacon pork loin pig, flank porchetta andouille sausage. T-bone alcatra rump pancetta landjaeger ground round cupim prosciutto shankle ham burgdoggen flank.

+

Jerky turkey pork, burgdoggen shank filet mignon corned beef ham chislic flank prosciutto kielbasa frankfurter. Turkey bresaola salami spare ribs rump, prosciutto short loin strip steak andouille filet mignon tenderloin kielbasa. Flank jowl fatback rump spare ribs. Jowl meatball leberkas rump. Doner buffalo bacon beef pig tail porchetta biltong boudin alcatra pork belly.

+

Porchetta biltong tri-tip kielbasa short ribs ham ground round t-bone venison. Prosciutto hamburger biltong, meatball tongue drumstick ham hock beef ribs. Porchetta jowl boudin, spare ribs tri-tip tenderloin meatloaf shankle landjaeger. Filet mignon meatball ribeye, hamburger kevin turkey cow.

+

Kevin andouille sausage pancetta chuck porchetta alcatra meatloaf. Cupim picanha short loin prosciutto leberkas pork, doner ham hock buffalo shankle tongue. Brisket hamburger tail beef chicken shankle capicola meatloaf pork loin porchetta t-bone. Shankle ham hock jowl ham. Sirloin sausage jerky t-bone.

+

Jowl bresaola alcatra pastrami pork belly rump short loin shoulder swine jerky flank sirloin andouille. Spare ribs sausage fatback venison flank pancetta. Pork chop ground round sirloin pork belly turkey swine buffalo tri-tip frankfurter landjaeger tongue turducken ball tip. Sirloin jerky meatloaf boudin.

+

Biltong turducken swine venison bacon, hamburger corned beef pork chop ham hock. Strip steak t-bone ham hock shoulder turducken leberkas chislic sirloin biltong pork belly kielbasa burgdoggen buffalo. T-bone frankfurter jerky, shoulder andouille short ribs rump meatloaf kevin swine tongue. Sirloin corned beef sausage, filet mignon picanha short loin bresaola alcatra boudin strip steak turducken.

+ } +} diff --git a/app/templates/about_templ.go b/app/templates/about_templ.go new file mode 100644 index 0000000..a41d843 --- /dev/null +++ b/app/templates/about_templ.go @@ -0,0 +1,140 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.513 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +func About(pc PageContext) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var3 := `Bacon ipsum dolor amet cow capicola pancetta picanha biltong brisket filet mignon turducken beef ribs burgdoggen landjaeger meatball venison shank. Capicola ham pork chop, biltong kielbasa pancetta short loin jowl cupim pig jerky drumstick turducken burgdoggen beef. Spare ribs flank ribeye cow doner, shank chuck bacon ham hock porchetta kielbasa tri-tip. Ham t-bone chislic, capicola andouille ham hock frankfurter tri-tip sausage kevin landjaeger shank ribeye. Swine tri-tip spare ribs, rump flank bresaola kevin tail. Meatball tail picanha cow, frankfurter ribeye sirloin pork belly short loin pig. Filet mignon spare ribs pastrami, tri-tip ball tip tongue fatback pork chop.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var4 := `Cupim biltong salami meatball ball tip buffalo, shoulder tenderloin beef ribs porchetta tail boudin chislic. Pastrami short ribs bresaola spare ribs, ham landjaeger brisket flank buffalo sirloin meatloaf tail chislic kielbasa. Leberkas t-bone hamburger pastrami, tri-tip tenderloin spare ribs alcatra filet mignon swine. Pork chop meatball buffalo alcatra cow beef, spare ribs pork loin pork ball tip corned beef sirloin pork belly fatback ham hock. Meatball ham hock filet mignon frankfurter, burgdoggen swine shankle pork belly chuck buffalo andouille corned beef pastrami turkey. Andouille short loin capicola tail pork belly biltong.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var5 := `Frankfurter t-bone hamburger meatball tongue capicola. Sausage beef ribs pig, landjaeger salami kielbasa shank cow strip steak doner brisket drumstick sirloin. Ground round ham pork belly pig tri-tip, pastrami ham hock. Bacon shankle brisket rump pork loin drumstick. Chicken shankle picanha corned beef sirloin. Venison kevin jerky ham kielbasa. Prosciutto pork chop brisket pork belly.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var6 := `Landjaeger tenderloin t-bone turkey buffalo, turducken beef ribs ham hock chuck frankfurter strip steak. Chuck frankfurter jowl jerky tri-tip bacon cow ribeye buffalo capicola bresaola drumstick beef ribs pork belly. Pig brisket tail prosciutto cupim andouille. Venison ground round kielbasa prosciutto jerky spare ribs. Meatball sirloin jerky, turducken tri-tip kevin brisket pork chop sausage rump. Ball tip pork loin frankfurter pig, capicola prosciutto tail bacon short ribs. Chislic porchetta meatloaf, picanha spare ribs kielbasa beef kevin capicola pork loin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var7 := `Tenderloin corned beef prosciutto fatback salami porchetta capicola meatball chuck jowl pork loin shoulder short ribs. Ham hock doner biltong, salami cow jerky bresaola drumstick short loin shankle chuck andouille ground round buffalo. Shankle pork belly landjaeger, corned beef hamburger sausage sirloin swine filet mignon short loin kevin. Jowl picanha pork chop meatball salami corned beef kielbasa. Ribeye leberkas bacon pork loin pig, flank porchetta andouille sausage. T-bone alcatra rump pancetta landjaeger ground round cupim prosciutto shankle ham burgdoggen flank.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var8 := `Jerky turkey pork, burgdoggen shank filet mignon corned beef ham chislic flank prosciutto kielbasa frankfurter. Turkey bresaola salami spare ribs rump, prosciutto short loin strip steak andouille filet mignon tenderloin kielbasa. Flank jowl fatback rump spare ribs. Jowl meatball leberkas rump. Doner buffalo bacon beef pig tail porchetta biltong boudin alcatra pork belly.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var9 := `Porchetta biltong tri-tip kielbasa short ribs ham ground round t-bone venison. Prosciutto hamburger biltong, meatball tongue drumstick ham hock beef ribs. Porchetta jowl boudin, spare ribs tri-tip tenderloin meatloaf shankle landjaeger. Filet mignon meatball ribeye, hamburger kevin turkey cow.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var10 := `Kevin andouille sausage pancetta chuck porchetta alcatra meatloaf. Cupim picanha short loin prosciutto leberkas pork, doner ham hock buffalo shankle tongue. Brisket hamburger tail beef chicken shankle capicola meatloaf pork loin porchetta t-bone. Shankle ham hock jowl ham. Sirloin sausage jerky t-bone.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var11 := `Jowl bresaola alcatra pastrami pork belly rump short loin shoulder swine jerky flank sirloin andouille. Spare ribs sausage fatback venison flank pancetta. Pork chop ground round sirloin pork belly turkey swine buffalo tri-tip frankfurter landjaeger tongue turducken ball tip. Sirloin jerky meatloaf boudin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var12 := `Biltong turducken swine venison bacon, hamburger corned beef pork chop ham hock. Strip steak t-bone ham hock shoulder turducken leberkas chislic sirloin biltong pork belly kielbasa burgdoggen buffalo. T-bone frankfurter jerky, shoulder andouille short ribs rump meatloaf kevin swine tongue. Sirloin corned beef sausage, filet mignon picanha short loin bresaola alcatra boudin strip steak turducken.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = baseLayout(pc).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/app/templates/home.templ b/app/templates/home.templ new file mode 100644 index 0000000..8ca3c76 --- /dev/null +++ b/app/templates/home.templ @@ -0,0 +1,11 @@ +package templates + +templ Home(pc PageContext) { + @baseLayout(pc) { +

Bacon ipsum dolor amet venison bacon picanha jerky tenderloin. Hamburger sausage meatball chislic salami. Ball tip tenderloin chuck, venison strip steak kielbasa short loin bresaola short ribs cupim drumstick shoulder pork t-bone. Burgdoggen cupim meatball picanha meatloaf, jowl leberkas kevin. T-bone jowl ham hock salami tenderloin.

+

Beef ribs frankfurter corned beef ground round pork, sausage drumstick. Corned beef turducken beef ribs, tongue burgdoggen capicola kielbasa short loin pork belly tail frankfurter ribeye strip steak meatloaf. Alcatra frankfurter salami cupim strip steak leberkas jerky ham hock biltong swine ball tip prosciutto t-bone andouille. Pork loin hamburger chuck frankfurter ham shankle jowl sausage chislic chicken tenderloin. Capicola tongue beef ribs flank, doner sirloin tri-tip pastrami. Porchetta andouille pork fatback jerky, pancetta pig filet mignon leberkas kielbasa sirloin.

+

Biltong landjaeger drumstick meatball boudin pork chop turducken jerky hamburger filet mignon flank. Venison turducken pork belly, pork chop ground round buffalo strip steak ribeye alcatra pancetta flank salami chislic. Landjaeger flank andouille short ribs. Shoulder beef ribs chuck, corned beef frankfurter turducken prosciutto.

+

Beef ribs venison kielbasa, swine andouille ground round cupim shoulder boudin corned beef bacon spare ribs doner strip steak. Pork ribeye flank, chislic fatback sausage alcatra beef ribs beef pork chop buffalo pancetta turducken short ribs. Shoulder ground round chislic filet mignon tri-tip turducken leberkas tenderloin tongue strip steak. Rump bresaola tenderloin, beef ribs buffalo sirloin tail venison porchetta biltong sausage kevin. Chicken kielbasa beef ribs, capicola ham hock shoulder pork belly frankfurter turducken short ribs buffalo boudin.

+

Rump meatball shoulder pig cow pork belly jerky pork loin salami corned beef biltong. Pancetta ham hock beef ribs corned beef landjaeger rump shoulder tongue kevin short loin. Pork chop pork loin beef ribs frankfurter bacon cow turkey ham flank pork rump. Sirloin burgdoggen chuck picanha pork ham hock pig tongue pastrami doner meatloaf rump. Prosciutto meatball fatback t-bone bacon biltong pork. Pastrami andouille pig strip steak, ground round corned beef ham hock shankle prosciutto. Pancetta alcatra jerky chislic short ribs.

+ } +} diff --git a/app/templates/home_templ.go b/app/templates/home_templ.go new file mode 100644 index 0000000..9db1acd --- /dev/null +++ b/app/templates/home_templ.go @@ -0,0 +1,95 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.513 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +func Home(pc PageContext) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var3 := `Bacon ipsum dolor amet venison bacon picanha jerky tenderloin. Hamburger sausage meatball chislic salami. Ball tip tenderloin chuck, venison strip steak kielbasa short loin bresaola short ribs cupim drumstick shoulder pork t-bone. Burgdoggen cupim meatball picanha meatloaf, jowl leberkas kevin. T-bone jowl ham hock salami tenderloin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var4 := `Beef ribs frankfurter corned beef ground round pork, sausage drumstick. Corned beef turducken beef ribs, tongue burgdoggen capicola kielbasa short loin pork belly tail frankfurter ribeye strip steak meatloaf. Alcatra frankfurter salami cupim strip steak leberkas jerky ham hock biltong swine ball tip prosciutto t-bone andouille. Pork loin hamburger chuck frankfurter ham shankle jowl sausage chislic chicken tenderloin. Capicola tongue beef ribs flank, doner sirloin tri-tip pastrami. Porchetta andouille pork fatback jerky, pancetta pig filet mignon leberkas kielbasa sirloin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var5 := `Biltong landjaeger drumstick meatball boudin pork chop turducken jerky hamburger filet mignon flank. Venison turducken pork belly, pork chop ground round buffalo strip steak ribeye alcatra pancetta flank salami chislic. Landjaeger flank andouille short ribs. Shoulder beef ribs chuck, corned beef frankfurter turducken prosciutto.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var5) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var6 := `Beef ribs venison kielbasa, swine andouille ground round cupim shoulder boudin corned beef bacon spare ribs doner strip steak. Pork ribeye flank, chislic fatback sausage alcatra beef ribs beef pork chop buffalo pancetta turducken short ribs. Shoulder ground round chislic filet mignon tri-tip turducken leberkas tenderloin tongue strip steak. Rump bresaola tenderloin, beef ribs buffalo sirloin tail venison porchetta biltong sausage kevin. Chicken kielbasa beef ribs, capicola ham hock shoulder pork belly frankfurter turducken short ribs buffalo boudin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var7 := `Rump meatball shoulder pig cow pork belly jerky pork loin salami corned beef biltong. Pancetta ham hock beef ribs corned beef landjaeger rump shoulder tongue kevin short loin. Pork chop pork loin beef ribs frankfurter bacon cow turkey ham flank pork rump. Sirloin burgdoggen chuck picanha pork ham hock pig tongue pastrami doner meatloaf rump. Prosciutto meatball fatback t-bone bacon biltong pork. Pastrami andouille pig strip steak, ground round corned beef ham hock shankle prosciutto. Pancetta alcatra jerky chislic short ribs.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var7) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = baseLayout(pc).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/app/templates/interactive.templ b/app/templates/interactive.templ new file mode 100644 index 0000000..b8a5127 --- /dev/null +++ b/app/templates/interactive.templ @@ -0,0 +1,229 @@ +package templates + +import ( + "fiber-sessions/app/types" + "fiber-sessions/app/data" + "slices" + "sort" +) + +templ interactiveButtonsSection() { +

+ Interactive buttons +

+ + + +

+ Bacon ipsum dolor amet cow capicola pancetta picanha biltong brisket filet mignon turducken beef ribs burgdoggen landjaeger meatball venison shank. Capicola ham pork chop, biltong kielbasa pancetta short loin jowl cupim pig jerky drumstick turducken burgdoggen beef. Spare ribs flank ribeye cow doner, shank chuck bacon ham hock porchetta kielbasa tri-tip. Ham t-bone chislic, capicola andouille ham hock frankfurter tri-tip sausage kevin landjaeger shank ribeye. Swine tri-tip spare ribs, rump flank bresaola kevin tail. Meatball tail picanha cow, frankfurter ribeye sirloin pork belly short loin pig. Filet mignon spare ribs pastrami, tri-tip ball tip tongue fatback pork chop. +

+} + +func getCatCountriesOptions() []string { + var res []string = []string{} + + for _, cb := range data.CatBreeds { + if len(cb.Country) > 0 && !slices.Contains(res, cb.Country) { + res = append(res, cb.Country) + } + } + + sort.Strings(res) + + return res +} + +templ catBreedsSection(catBreeds []types.CatBreed) { +

+ Cat breeds +

+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ @catBreedsTable(catBreeds) +} + +templ catBreedsTable(catBreeds []types.CatBreed) { + + + + + + + + + + + + for _, breed := range catBreeds { + + + + + + + + } + +
BreedCountryOriginCoatPattern
{ breed.Breed }{ breed.Country }{ breed.Origin }{ breed.Coat }{ breed.Pattern }
+} + +templ InteractiveSwapContent(pc PageContext, contentIndex int) { + switch contentIndex { + case 1: +

+ Bacon ipsum dolor amet t-bone meatball corned beef hamburger cupim rump drumstick tri-tip doner pastrami kielbasa salami pig. Pork loin doner leberkas, jerky fatback chuck corned beef cow rump strip steak shoulder pork belly. Flank hamburger porchetta shank sirloin bresaola chislic pork chop. Chicken jerky strip steak tongue jowl brisket cupim. Shankle t-bone short ribs fatback burgdoggen buffalo cupim prosciutto meatball pig doner boudin. +

+ case 2: +

+ Rump venison tenderloin, picanha ribeye cupim pork belly sirloin landjaeger jerky prosciutto filet mignon alcatra. Short ribs pork chop rump kevin t-bone ground round hamburger, chislic tenderloin bacon sirloin filet mignon turducken beef pork loin. Buffalo picanha ground round pork chop. Venison cupim pork belly, andouille pastrami tail shankle pancetta. Picanha leberkas cupim turkey buffalo filet mignon pork belly pork chop rump sausage pork loin. Short ribs burgdoggen porchetta hamburger, cupim ribeye capicola shoulder. Pork drumstick kevin, turkey hamburger ground round burgdoggen chuck jerky bacon sausage chislic leberkas. +

+ case 3: +

+ Biltong ham hock tongue, beef pork andouille fatback flank pork loin ribeye. Rump short loin porchetta, ground round buffalo hamburger salami pig venison beef ribs. Chislic beef ribs sausage fatback pork belly. Ribeye porchetta leberkas, tail hamburger biltong landjaeger short loin filet mignon chicken salami flank. +

+ default: +

+ Some new content with unknown index... +

+ } +} + +templ RenderCatBreedsTable(catBreeds []types.CatBreed) { + @catBreedsTable(catBreeds) +} + +templ RenderInteractiveForm(content ValidateFormContent) { +
+
+
+ + + if content.HasNumValueError { +
{ content.NumValueError }
+ } +
+
+
+
+ + + if content.HasStrValueError { +
{ content.StrValueError }
+ } +
+
+
+} + +templ interactiveFormSection() { +

+ Form validation +

+
+
+ @RenderInteractiveForm(ValidateFormContent{}) +
+ +
+
+
+} + +templ Interactive(pc PageContext, catBreeds []types.CatBreed) { + @baseLayout(pc) { +
+
+ @interactiveButtonsSection() +
+
+ @interactiveFormSection() +
+
+ @catBreedsSection(catBreeds) + } +} diff --git a/app/templates/interactive_templ.go b/app/templates/interactive_templ.go new file mode 100644 index 0000000..25f8297 --- /dev/null +++ b/app/templates/interactive_templ.go @@ -0,0 +1,693 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.513 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "fiber-sessions/app/data" + "fiber-sessions/app/types" + "slices" + "sort" +) + +func interactiveButtonsSection() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var2 := `Interactive buttons` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var2) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var6 := `Bacon ipsum dolor amet cow capicola pancetta picanha biltong brisket filet mignon turducken beef ribs burgdoggen landjaeger meatball venison shank. Capicola ham pork chop, biltong kielbasa pancetta short loin jowl cupim pig jerky drumstick turducken burgdoggen beef. Spare ribs flank ribeye cow doner, shank chuck bacon ham hock porchetta kielbasa tri-tip. Ham t-bone chislic, capicola andouille ham hock frankfurter tri-tip sausage kevin landjaeger shank ribeye. Swine tri-tip spare ribs, rump flank bresaola kevin tail. Meatball tail picanha cow, frankfurter ribeye sirloin pork belly short loin pig. Filet mignon spare ribs pastrami, tri-tip ball tip tongue fatback pork chop.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var6) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func getCatCountriesOptions() []string { + var res []string = []string{} + + for _, cb := range data.CatBreeds { + if len(cb.Country) > 0 && !slices.Contains(res, cb.Country) { + res = append(res, cb.Country) + } + } + + sort.Strings(res) + + return res +} + +func catBreedsSection(catBreeds []types.CatBreed) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var8 := `Cat breeds` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = catBreedsTable(catBreeds).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func catBreedsTable(catBreeds []types.CatBreed) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, breed := range catBreeds { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var14 := `Breed` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var14) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var15 := `Country` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var16 := `Origin` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var16) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var17 := `Coat` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var17) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var18 := `Pattern` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var18) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(breed.Breed) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 121, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var20 string + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(breed.Country) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 122, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var21 string + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(breed.Origin) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 123, Col: 23} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 string + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(breed.Coat) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 124, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(breed.Pattern) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 125, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func InteractiveSwapContent(pc PageContext, contentIndex int) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var24 := templ.GetChildren(ctx) + if templ_7745c5c3_Var24 == nil { + templ_7745c5c3_Var24 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch contentIndex { + case 1: + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var25 := `Bacon ipsum dolor amet t-bone meatball corned beef hamburger cupim rump drumstick tri-tip doner pastrami kielbasa salami pig. Pork loin doner leberkas, jerky fatback chuck corned beef cow rump strip steak shoulder pork belly. Flank hamburger porchetta shank sirloin bresaola chislic pork chop. Chicken jerky strip steak tongue jowl brisket cupim. Shankle t-bone short ribs fatback burgdoggen buffalo cupim prosciutto meatball pig doner boudin.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var25) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + case 2: + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var26 := `Rump venison tenderloin, picanha ribeye cupim pork belly sirloin landjaeger jerky prosciutto filet mignon alcatra. Short ribs pork chop rump kevin t-bone ground round hamburger, chislic tenderloin bacon sirloin filet mignon turducken beef pork loin. Buffalo picanha ground round pork chop. Venison cupim pork belly, andouille pastrami tail shankle pancetta. Picanha leberkas cupim turkey buffalo filet mignon pork belly pork chop rump sausage pork loin. Short ribs burgdoggen porchetta hamburger, cupim ribeye capicola shoulder. Pork drumstick kevin, turkey hamburger ground round burgdoggen chuck jerky bacon sausage chislic leberkas.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var26) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + case 3: + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var27 := `Biltong ham hock tongue, beef pork andouille fatback flank pork loin ribeye. Rump short loin porchetta, ground round buffalo hamburger salami pig venison beef ribs. Chislic beef ribs sausage fatback pork belly. Ribeye porchetta leberkas, tail hamburger biltong landjaeger short loin filet mignon chicken salami flank.` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var27) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var28 := `Some new content with unknown index...` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func RenderCatBreedsTable(catBreeds []types.CatBreed) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var29 := templ.GetChildren(ctx) + if templ_7745c5c3_Var29 == nil { + templ_7745c5c3_Var29 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = catBreedsTable(catBreeds).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func RenderInteractiveForm(content ValidateFormContent) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var30 := templ.GetChildren(ctx) + if templ_7745c5c3_Var30 == nil { + templ_7745c5c3_Var30 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var32 = []any{"form-control", + templ.KV("is-invalid", content.HasNumValueError), + templ.KV("is-valid", content.Validated && !content.HasNumValueError)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var32...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if content.HasNumValueError { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var33 string + templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(content.NumValueError) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 172, Col: 58} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var35 = []any{"form-control", + templ.KV("is-invalid", content.HasStrValueError), + templ.KV("is-valid", content.Validated && !content.HasStrValueError)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var35...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if content.HasStrValueError { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var36 string + templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(content.StrValueError) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/interactive.templ`, Line: 189, Col: 58} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func interactiveFormSection() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var37 := templ.GetChildren(ctx) + if templ_7745c5c3_Var37 == nil { + templ_7745c5c3_Var37 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var38 := `Form validation` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var38) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = RenderInteractiveForm(ValidateFormContent{}).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func Interactive(pc PageContext, catBreeds []types.CatBreed) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var40 := templ.GetChildren(ctx) + if templ_7745c5c3_Var40 == nil { + templ_7745c5c3_Var40 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var41 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = interactiveButtonsSection().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = interactiveFormSection().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = catBreedsSection(catBreeds).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = baseLayout(pc).Render(templ.WithChildren(ctx, templ_7745c5c3_Var41), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/app/templates/layout.templ b/app/templates/layout.templ new file mode 100644 index 0000000..e2a9811 --- /dev/null +++ b/app/templates/layout.templ @@ -0,0 +1,45 @@ +package templates + +templ baseLayout(pc PageContext) { + + + + + + + + + { pc.Title } + + +
+

+ Go + templ + htmx demo +

+ + if pc.User != nil { +

+ Hello, { pc.User.FirstName } +

+ } + { children... } +
+ + +} diff --git a/app/templates/layout_templ.go b/app/templates/layout_templ.go new file mode 100644 index 0000000..ee47f0e --- /dev/null +++ b/app/templates/layout_templ.go @@ -0,0 +1,176 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.513 +package templates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +func baseLayout(pc PageContext) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(pc.Title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/layout.templ`, Line: 11, Col: 20} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var4 := `Go + templ + htmx demo` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var4) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if pc.User != nil { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var11 := `Hello, ` + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(pc.User.FirstName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `app/templates/layout.templ`, Line: 37, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/app/templates/types.go b/app/templates/types.go new file mode 100644 index 0000000..069693f --- /dev/null +++ b/app/templates/types.go @@ -0,0 +1,21 @@ +package templates + +import "fiber-sessions/app/types" + +type PageContext struct { + Title string + ActivePage string + User *types.User +} + +type ValidateFormContent struct { + Validated bool + + StrValue string + HasStrValueError bool + StrValueError string + + NumValue string + HasNumValueError bool + NumValueError string +} diff --git a/app/types/catbreed.go b/app/types/catbreed.go new file mode 100644 index 0000000..0219d6b --- /dev/null +++ b/app/types/catbreed.go @@ -0,0 +1,9 @@ +package types + +type CatBreed struct { + Breed string + Country string + Origin string + Coat string + Pattern string +} diff --git a/app/types/user.go b/app/types/user.go new file mode 100644 index 0000000..538a7ab --- /dev/null +++ b/app/types/user.go @@ -0,0 +1,6 @@ +package types + +type User struct { + FirstName string + LastName string +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cf76433 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module fiber-sessions + +go 1.21.6 + +require ( + github.com/a-h/templ v0.2.513 + github.com/gofiber/fiber/v2 v2.52.0 +) + +require ( + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/klauspost/compress v1.17.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/sys v0.16.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d5e90d0 --- /dev/null +++ b/go.sum @@ -0,0 +1,41 @@ +github.com/a-h/templ v0.2.513 h1:ZmwGAOx4NYllnHy+FTpusc4+c5msoMpPIYX0Oy3dNqw= +github.com/a-h/templ v0.2.513/go.mod h1:9gZxTLtRzM3gQxO8jr09Na0v8/jfliS97S9W5SScanM= +github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk= +github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= +github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg= +github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/static/js/htmx.min.js b/static/js/htmx.min.js new file mode 100644 index 0000000..47eb70f --- /dev/null +++ b/static/js/htmx.min.js @@ -0,0 +1 @@ +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var Q={onLoad:F,process:zt,on:de,off:ge,trigger:ce,ajax:Nr,find:C,findAll:f,closest:v,values:function(e,t){var r=dr(e,t||"post");return r.values},remove:_,addClass:z,removeClass:n,toggleClass:$,takeClass:W,defineExtension:Ur,removeExtension:Br,logAll:V,logNone:j,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get"],selfRequestsOnly:false,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null},parseInterval:d,_:t,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=Q.config.wsBinaryType;return t},version:"1.9.10"};var r={addTriggerHandler:Lt,bodyContains:se,canAccessLocalStorage:U,findThisElement:xe,filterValues:yr,hasAttribute:o,getAttributeValue:te,getClosestAttributeValue:ne,getClosestMatch:c,getExpressionVars:Hr,getHeaders:xr,getInputValues:dr,getInternalData:ae,getSwapSpecification:wr,getTriggerSpecs:it,getTarget:ye,makeFragment:l,mergeObjects:le,makeSettleInfo:T,oobSwap:Ee,querySelectorExt:ue,selectAndSwap:je,settleImmediately:nr,shouldCancel:ut,triggerEvent:ce,triggerErrorEvent:fe,withExtensions:R};var w=["get","post","put","delete","patch"];var i=w.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");var S=e("head"),q=e("title"),H=e("svg",true);function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e.getAttribute&&e.getAttribute(t)}function o(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){return e.parentElement}function re(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function L(e,t,r){var n=te(t,r);var i=te(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function ne(t,r){var n=null;c(t,function(e){return n=L(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function A(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function a(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=re().createDocumentFragment()}return i}function N(e){return/",0);return i.querySelector("template").content}switch(r){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return a(""+n+"
",1);case"col":return a(""+n+"
",2);case"tr":return a(""+n+"
",2);case"td":case"th":return a(""+n+"
",3);case"script":case"style":return a("
"+n+"
",1);default:return a(n,0)}}function ie(e){if(e){e()}}function I(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return I(e,"Function")}function P(e){return I(e,"Object")}function ae(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function M(e){var t=[];if(e){for(var r=0;r=0}function se(e){if(e.getRootNode&&e.getRootNode()instanceof window.ShadowRoot){return re().body.contains(e.getRootNode().host)}else{return re().body.contains(e)}}function D(e){return e.trim().split(/\s+/)}function le(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){try{return JSON.parse(e)}catch(e){b(e);return null}}function U(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function B(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function t(e){return Tr(re().body,function(){return eval(e)})}function F(t){var e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function j(){Q.logger=null}function C(e,t){if(t){return e.querySelector(t)}else{return C(re(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(re(),e)}}function _(e,t){e=g(e);if(t){setTimeout(function(){_(e);e=null},t)}else{e.parentElement.removeChild(e)}}function z(e,t,r){e=g(e);if(r){setTimeout(function(){z(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=g(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function $(e,t){e=g(e);e.classList.toggle(t)}function W(e,t){e=g(e);oe(e.parentElement.children,function(e){n(e,t)});z(e,t)}function v(e,t){e=g(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function s(e,t){return e.substring(0,t.length)===t}function G(e,t){return e.substring(e.length-t.length)===t}function J(e){var t=e.trim();if(s(t,"<")&&G(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function Z(e,t){if(t.indexOf("closest ")===0){return[v(e,J(t.substr(8)))]}else if(t.indexOf("find ")===0){return[C(e,J(t.substr(5)))]}else if(t==="next"){return[e.nextElementSibling]}else if(t.indexOf("next ")===0){return[K(e,J(t.substr(5)))]}else if(t==="previous"){return[e.previousElementSibling]}else if(t.indexOf("previous ")===0){return[Y(e,J(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else if(t==="body"){return[document.body]}else{return re().querySelectorAll(J(t))}}var K=function(e,t){var r=re().querySelectorAll(t);for(var n=0;n=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function ue(e,t){if(t){return Z(e,t)[0]}else{return Z(re().body,e)[0]}}function g(e){if(I(e,"String")){return C(e)}else{return e}}function ve(e,t,r){if(k(t)){return{target:re().body,event:e,listener:t}}else{return{target:g(e),event:t,listener:r}}}function de(t,r,n){jr(function(){var e=ve(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=k(r);return e?r:n}function ge(t,r,n){jr(function(){var e=ve(t,r,n);e.target.removeEventListener(e.event,e.listener)});return k(r)?r:n}var me=re().createElement("output");function pe(e,t){var r=ne(e,t);if(r){if(r==="this"){return[xe(e,t)]}else{var n=Z(e,r);if(n.length===0){b('The selector "'+r+'" on '+t+" returned no matches!");return[me]}else{return n}}}}function xe(e,t){return c(e,function(e){return te(e,t)!=null})}function ye(e){var t=ne(e,"hx-target");if(t){if(t==="this"){return xe(e,"hx-target")}else{return ue(e,t)}}else{var r=ae(e);if(r.boosted){return re().body}else{return e}}}function be(e){var t=Q.config.attributesToSettle;for(var r=0;r0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=re().querySelectorAll(t);if(r){oe(r,function(e){var t;var r=i.cloneNode(true);t=re().createDocumentFragment();t.appendChild(r);if(!Se(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ce(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){Fe(o,e,e,t,a)}oe(a.elts,function(e){ce(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);fe(re().body,"htmx:oobErrorNoTarget",{content:i})}return e}function Ce(e,t,r){var n=ne(e,"hx-select-oob");if(n){var i=n.split(",");for(var a=0;a0){var r=t.replace("'","\\'");var n=e.tagName.replace(":","\\:");var i=o.querySelector(n+"[id='"+r+"']");if(i&&i!==o){var a=e.cloneNode();we(e,i);s.tasks.push(function(){we(e,a)})}}})}function Oe(e){return function(){n(e,Q.config.addedClass);zt(e);Nt(e);qe(e);ce(e,"htmx:load")}}function qe(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function m(e,t,r,n){Te(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;z(i,Q.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(Oe(i))}}}function He(e,t){var r=0;while(r-1){var t=e.replace(H,"");var r=t.match(q);if(r){return r[2]}}}function je(e,t,r,n,i,a){i.title=Ve(n);var o=l(n);if(o){Ce(r,o,i);o=Be(r,o,a);Re(o);return Fe(e,r,t,o,i)}}function _e(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=E(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!P(o)){o={value:o}}ce(r,a,o)}}}else{var s=n.split(",");for(var l=0;l0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=Tr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){fe(re().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Qe(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function y(e,t){var r="";while(e.length>0&&!t.test(e[0])){r+=e.shift()}return r}function tt(e){var t;if(e.length>0&&Ze.test(e[0])){e.shift();t=y(e,Ke).trim();e.shift()}else{t=y(e,x)}return t}var rt="input, textarea, select";function nt(e,t,r){var n=[];var i=Ye(t);do{y(i,Je);var a=i.length;var o=y(i,/[,\[\s]/);if(o!==""){if(o==="every"){var s={trigger:"every"};y(i,Je);s.pollInterval=d(y(i,/[,\[\s]/));y(i,Je);var l=et(e,i,"event");if(l){s.eventFilter=l}n.push(s)}else if(o.indexOf("sse:")===0){n.push({trigger:"sse",sseEvent:o.substr(4)})}else{var u={trigger:o};var l=et(e,i,"event");if(l){u.eventFilter=l}while(i.length>0&&i[0]!==","){y(i,Je);var f=i.shift();if(f==="changed"){u.changed=true}else if(f==="once"){u.once=true}else if(f==="consume"){u.consume=true}else if(f==="delay"&&i[0]===":"){i.shift();u.delay=d(y(i,x))}else if(f==="from"&&i[0]===":"){i.shift();if(Ze.test(i[0])){var c=tt(i)}else{var c=y(i,x);if(c==="closest"||c==="find"||c==="next"||c==="previous"){i.shift();var h=tt(i);if(h.length>0){c+=" "+h}}}u.from=c}else if(f==="target"&&i[0]===":"){i.shift();u.target=tt(i)}else if(f==="throttle"&&i[0]===":"){i.shift();u.throttle=d(y(i,x))}else if(f==="queue"&&i[0]===":"){i.shift();u.queue=y(i,x)}else if(f==="root"&&i[0]===":"){i.shift();u[f]=tt(i)}else if(f==="threshold"&&i[0]===":"){i.shift();u[f]=y(i,x)}else{fe(e,"htmx:syntax:error",{token:i.shift()})}}n.push(u)}}if(i.length===a){fe(e,"htmx:syntax:error",{token:i.shift()})}y(i,Je)}while(i[0]===","&&i.shift());if(r){r[t]=n}return n}function it(e){var t=te(e,"hx-trigger");var r=[];if(t){var n=Q.config.triggerSpecsCache;r=n&&n[t]||nt(e,t,n)}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,rt)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function at(e){ae(e).cancelled=true}function ot(e,t,r){var n=ae(e);n.timeout=setTimeout(function(){if(se(e)&&n.cancelled!==true){if(!ct(r,e,Wt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}ot(e,t,r)}},r.pollInterval)}function st(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function lt(t,r,e){if(t.tagName==="A"&&st(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=ee(t,"href")}else{var a=ee(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=ee(t,"action")}e.forEach(function(e){ht(t,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(n,i,e,t)},r,e,true)})}}function ut(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&v(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function ft(e,t){return ae(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function ct(e,t,r){var n=e.eventFilter;if(n){try{return n.call(t,r)!==true}catch(e){fe(re().body,"htmx:eventFilter:error",{error:e,source:n.source});return true}}return false}function ht(a,o,e,s,l){var u=ae(a);var t;if(s.from){t=Z(a,s.from)}else{t=[a]}if(s.changed){t.forEach(function(e){var t=ae(e);t.lastValue=e.value})}oe(t,function(n){var i=function(e){if(!se(a)){n.removeEventListener(s.trigger,i);return}if(ft(a,e)){return}if(l||ut(e,a)){e.preventDefault()}if(ct(s,a,e)){return}var t=ae(e);t.triggerSpec=s;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(a)<0){t.handledFor.push(a);if(s.consume){e.stopPropagation()}if(s.target&&e.target){if(!h(e.target,s.target)){return}}if(s.once){if(u.triggeredOnce){return}else{u.triggeredOnce=true}}if(s.changed){var r=ae(n);if(r.lastValue===n.value){return}r.lastValue=n.value}if(u.delayed){clearTimeout(u.delayed)}if(u.throttle){return}if(s.throttle>0){if(!u.throttle){o(a,e);u.throttle=setTimeout(function(){u.throttle=null},s.throttle)}}else if(s.delay>0){u.delayed=setTimeout(function(){o(a,e)},s.delay)}else{ce(a,"htmx:trigger");o(a,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:s.trigger,listener:i,on:n});n.addEventListener(s.trigger,i)})}var vt=false;var dt=null;function gt(){if(!dt){dt=function(){vt=true};window.addEventListener("scroll",dt);setInterval(function(){if(vt){vt=false;oe(re().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){mt(e)})}},200)}}function mt(t){if(!o(t,"data-hx-revealed")&&X(t)){t.setAttribute("data-hx-revealed","true");var e=ae(t);if(e.initHash){ce(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ce(t,"revealed")},{once:true})}}}function pt(e,t,r){var n=D(r);for(var i=0;i=0){var t=wt(n);setTimeout(function(){xt(s,r,n+1)},t)}};t.onopen=function(e){n=0};ae(s).webSocket=t;t.addEventListener("message",function(e){if(yt(s)){return}var t=e.data;R(s,function(e){t=e.transformResponse(t,null,s)});var r=T(s);var n=l(t);var i=M(n.children);for(var a=0;a0){ce(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(ut(e,u)){e.preventDefault()}})}else{fe(u,"htmx:noWebSocketSourceError")}}function wt(e){var t=Q.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}b('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function St(e,t,r){var n=D(r);for(var i=0;i0){setTimeout(i,n)}else{i()}}function Ht(t,i,e){var a=false;oe(w,function(r){if(o(t,"hx-"+r)){var n=te(t,"hx-"+r);a=true;i.path=n;i.verb=r;e.forEach(function(e){Lt(t,e,i,function(e,t){if(v(e,Q.config.disableSelector)){p(e);return}he(r,n,e,t)})})}});return a}function Lt(n,e,t,r){if(e.sseEvent){Rt(n,r,e.sseEvent)}else if(e.trigger==="revealed"){gt();ht(n,r,t,e);mt(n)}else if(e.trigger==="intersect"){var i={};if(e.root){i.root=ue(n,e.root)}if(e.threshold){i.threshold=parseFloat(e.threshold)}var a=new IntersectionObserver(function(e){for(var t=0;t0){t.polling=true;ot(n,r,e)}else{ht(n,r,t,e)}}function At(e){if(Q.config.allowScriptTags&&(e.type==="text/javascript"||e.type==="module"||e.type==="")){var t=re().createElement("script");oe(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}var r=e.parentElement;try{r.insertBefore(t,e)}catch(e){b(e)}finally{if(e.parentElement){e.parentElement.removeChild(e)}}}}function Nt(e){if(h(e,"script")){At(e)}oe(f(e,"script"),function(e){At(e)})}function It(e){var t=e.attributes;for(var r=0;r0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-\.]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Bt(o)}for(var l in r){Ft(e,l,r[l])}}}function jt(e){Ae(e);for(var t=0;tQ.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(re().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Yt(e){if(!U()){return null}e=B(e);var t=E(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){ce(re().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Zt();var r=T(t);var n=Ve(this.response);if(n){var i=C("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ue(t,e,r);nr(r.tasks);Jt=a;ce(re().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{fe(re().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function ar(e){er();e=e||location.pathname+location.search;var t=Yt(e);if(t){var r=l(t.content);var n=Zt();var i=T(n);Ue(n,r,i);nr(i.tasks);document.title=t.title;setTimeout(function(){window.scrollTo(0,t.scroll)},0);Jt=e;ce(re().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{ir(e)}}}function or(e){var t=pe(e,"hx-indicator");if(t==null){t=[e]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,Q.config.requestClass)});return t}function sr(e){var t=pe(e,"hx-disabled-elt");if(t==null){t=[]}oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","")});return t}function lr(e,t){oe(e,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,Q.config.requestClass)}});oe(t,function(e){var t=ae(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.removeAttribute("disabled")}})}function ur(e,t){for(var r=0;r=0}function wr(e,t){var r=t?t:ne(e,"hx-swap");var n={swapStyle:ae(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ae(e).boosted&&!br(e)){n["show"]="top"}if(r){var i=D(r);if(i.length>0){for(var a=0;a0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}else if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}else if(o.indexOf("focus-scroll:")===0){var v=o.substr("focus-scroll:".length);n["focusScroll"]=v=="true"}else if(a==0){n["swapStyle"]=o}else{b("Unknown modifier in hx-swap: "+o)}}}}return n}function Sr(e){return ne(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function Er(t,r,n){var i=null;R(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(Sr(r)){return pr(n)}else{return mr(n)}}}function T(e){return{tasks:[],elts:[e]}}function Cr(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=ue(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=ue(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function Rr(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=te(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=Tr(e,function(){return Function("return ("+a+")")()},{})}else{s=E(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return Rr(u(e),t,r,n)}function Tr(e,t,r){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return r}}function Or(e,t){return Rr(e,"hx-vars",true,t)}function qr(e,t){return Rr(e,"hx-vals",false,t)}function Hr(e){return le(Or(e),qr(e))}function Lr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function Ar(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(re().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function O(e,t){return t.test(e.getAllResponseHeaders())}function Nr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||I(r,"String")){return he(e,t,null,null,{targetOverride:g(r),returnPromise:true})}else{return he(e,t,g(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:g(r.target),swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return he(e,t,null,null,{returnPromise:true})}}function Ir(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function kr(e,t,r){var n;var i;if(typeof URL==="function"){i=new URL(t,document.location.href);var a=document.location.origin;n=a===i.origin}else{i=t;n=s(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!n){return false}}return ce(e,"htmx:validateUrl",le({url:i,sameHost:n},r))}function he(t,r,n,i,a,e){var o=null;var s=null;a=a!=null?a:{};if(a.returnPromise&&typeof Promise!=="undefined"){var l=new Promise(function(e,t){o=e;s=t})}if(n==null){n=re().body}var M=a.handler||Mr;var X=a.select||null;if(!se(n)){ie(o);return l}var u=a.targetOverride||ye(n);if(u==null||u==me){fe(n,"htmx:targetError",{target:te(n,"hx-target")});ie(s);return l}var f=ae(n);var c=f.lastButtonClicked;if(c){var h=ee(c,"formaction");if(h!=null){r=h}var v=ee(c,"formmethod");if(v!=null){if(v.toLowerCase()!=="dialog"){t=v}}}var d=ne(n,"hx-confirm");if(e===undefined){var D=function(e){return he(t,r,n,i,a,!!e)};var U={target:u,elt:n,path:r,verb:t,triggeringEvent:i,etc:a,issueRequest:D,question:d};if(ce(n,"htmx:confirm",U)===false){ie(o);return l}}var g=n;var m=ne(n,"hx-sync");var p=null;var x=false;if(m){var B=m.split(":");var F=B[0].trim();if(F==="this"){g=xe(n,"hx-sync")}else{g=ue(n,F)}m=(B[1]||"drop").trim();f=ae(g);if(m==="drop"&&f.xhr&&f.abortable!==true){ie(o);return l}else if(m==="abort"){if(f.xhr){ie(o);return l}else{x=true}}else if(m==="replace"){ce(g,"htmx:abort")}else if(m.indexOf("queue")===0){var V=m.split(" ");p=(V[1]||"last").trim()}}if(f.xhr){if(f.abortable){ce(g,"htmx:abort")}else{if(p==null){if(i){var y=ae(i);if(y&&y.triggerSpec&&y.triggerSpec.queue){p=y.triggerSpec.queue}}if(p==null){p="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(p==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="all"){f.queuedRequests.push(function(){he(t,r,n,i,a)})}else if(p==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){he(t,r,n,i,a)})}ie(o);return l}}var b=new XMLHttpRequest;f.xhr=b;f.abortable=x;var w=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var j=ne(n,"hx-prompt");if(j){var S=prompt(j);if(S===null||!ce(n,"htmx:prompt",{prompt:S,target:u})){ie(o);w();return l}}if(d&&!e){if(!confirm(d)){ie(o);w();return l}}var E=xr(n,u,S);if(t!=="get"&&!Sr(n)){E["Content-Type"]="application/x-www-form-urlencoded"}if(a.headers){E=le(E,a.headers)}var _=dr(n,t);var C=_.errors;var R=_.values;if(a.values){R=le(R,a.values)}var z=Hr(n);var $=le(R,z);var T=yr($,n);if(Q.config.getCacheBusterParam&&t==="get"){T["org.htmx.cache-buster"]=ee(u,"id")||"true"}if(r==null||r===""){r=re().location.href}var O=Rr(n,"hx-request");var W=ae(n).boosted;var q=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;var H={boosted:W,useUrlParams:q,parameters:T,unfilteredParameters:$,headers:E,target:u,verb:t,errors:C,withCredentials:a.credentials||O.credentials||Q.config.withCredentials,timeout:a.timeout||O.timeout||Q.config.timeout,path:r,triggeringEvent:i};if(!ce(n,"htmx:configRequest",H)){ie(o);w();return l}r=H.path;t=H.verb;E=H.headers;T=H.parameters;C=H.errors;q=H.useUrlParams;if(C&&C.length>0){ce(n,"htmx:validation:halted",H);ie(o);w();return l}var G=r.split("#");var J=G[0];var L=G[1];var A=r;if(q){A=J;var Z=Object.keys(T).length!==0;if(Z){if(A.indexOf("?")<0){A+="?"}else{A+="&"}A+=mr(T);if(L){A+="#"+L}}}if(!kr(n,A,H)){fe(n,"htmx:invalidPath",H);ie(s);return l}b.open(t.toUpperCase(),A,true);b.overrideMimeType("text/html");b.withCredentials=H.withCredentials;b.timeout=H.timeout;if(O.noHeaders){}else{for(var N in E){if(E.hasOwnProperty(N)){var K=E[N];Lr(b,N,K)}}}var I={xhr:b,target:u,requestConfig:H,etc:a,boosted:W,select:X,pathInfo:{requestPath:r,finalRequestPath:A,anchor:L}};b.onload=function(){try{var e=Ir(n);I.pathInfo.responsePath=Ar(b);M(n,I);lr(k,P);ce(n,"htmx:afterRequest",I);ce(n,"htmx:afterOnLoad",I);if(!se(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(se(r)){t=r}}if(t){ce(t,"htmx:afterRequest",I);ce(t,"htmx:afterOnLoad",I)}}ie(o);w()}catch(e){fe(n,"htmx:onLoadError",le({error:e},I));throw e}};b.onerror=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendError",I);ie(s);w()};b.onabort=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:sendAbort",I);ie(s);w()};b.ontimeout=function(){lr(k,P);fe(n,"htmx:afterRequest",I);fe(n,"htmx:timeout",I);ie(s);w()};if(!ce(n,"htmx:beforeRequest",I)){ie(o);w();return l}var k=or(n);var P=sr(n);oe(["loadstart","loadend","progress","abort"],function(t){oe([b,b.upload],function(e){e.addEventListener(t,function(e){ce(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ce(n,"htmx:beforeSend",I);var Y=q?null:Er(b,n,T);b.send(Y);return l}function Pr(e,t){var r=t.xhr;var n=null;var i=null;if(O(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(O(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(O(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=ne(e,"hx-push-url");var l=ne(e,"hx-replace-url");var u=ae(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function Mr(l,u){var f=u.xhr;var c=u.target;var e=u.etc;var t=u.requestConfig;var h=u.select;if(!ce(l,"htmx:beforeOnLoad",u))return;if(O(f,/HX-Trigger:/i)){_e(f,"HX-Trigger",l)}if(O(f,/HX-Location:/i)){er();var r=f.getResponseHeader("HX-Location");var v;if(r.indexOf("{")===0){v=E(r);r=v["path"];delete v["path"]}Nr("GET",r,v).then(function(){tr(r)});return}var n=O(f,/HX-Refresh:/i)&&"true"===f.getResponseHeader("HX-Refresh");if(O(f,/HX-Redirect:/i)){location.href=f.getResponseHeader("HX-Redirect");n&&location.reload();return}if(n){location.reload();return}if(O(f,/HX-Retarget:/i)){if(f.getResponseHeader("HX-Retarget")==="this"){u.target=l}else{u.target=ue(l,f.getResponseHeader("HX-Retarget"))}}var d=Pr(l,u);var i=f.status>=200&&f.status<400&&f.status!==204;var g=f.response;var a=f.status>=400;var m=Q.config.ignoreTitle;var o=le({shouldSwap:i,serverResponse:g,isError:a,ignoreTitle:m},u);if(!ce(c,"htmx:beforeSwap",o))return;c=o.target;g=o.serverResponse;a=o.isError;m=o.ignoreTitle;u.target=c;u.failed=a;u.successful=!a;if(o.shouldSwap){if(f.status===286){at(l)}R(l,function(e){g=e.transformResponse(g,f,l)});if(d.type){er()}var s=e.swapOverride;if(O(f,/HX-Reswap:/i)){s=f.getResponseHeader("HX-Reswap")}var v=wr(l,s);if(v.hasOwnProperty("ignoreTitle")){m=v.ignoreTitle}c.classList.add(Q.config.swappingClass);var p=null;var x=null;var y=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var r;if(h){r=h}if(O(f,/HX-Reselect:/i)){r=f.getResponseHeader("HX-Reselect")}if(d.type){ce(re().body,"htmx:beforeHistoryUpdate",le({history:d},u));if(d.type==="push"){tr(d.path);ce(re().body,"htmx:pushedIntoHistory",{path:d.path})}else{rr(d.path);ce(re().body,"htmx:replacedInHistory",{path:d.path})}}var n=T(c);je(v.swapStyle,c,l,g,n,r);if(t.elt&&!se(t.elt)&&ee(t.elt,"id")){var i=document.getElementById(ee(t.elt,"id"));var a={preventScroll:v.focusScroll!==undefined?!v.focusScroll:!Q.config.defaultFocusScroll};if(i){if(t.start&&i.setSelectionRange){try{i.setSelectionRange(t.start,t.end)}catch(e){}}i.focus(a)}}c.classList.remove(Q.config.swappingClass);oe(n.elts,function(e){if(e.classList){e.classList.add(Q.config.settlingClass)}ce(e,"htmx:afterSwap",u)});if(O(f,/HX-Trigger-After-Swap:/i)){var o=l;if(!se(l)){o=re().body}_e(f,"HX-Trigger-After-Swap",o)}var s=function(){oe(n.tasks,function(e){e.call()});oe(n.elts,function(e){if(e.classList){e.classList.remove(Q.config.settlingClass)}ce(e,"htmx:afterSettle",u)});if(u.pathInfo.anchor){var e=re().getElementById(u.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title&&!m){var t=C("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}Cr(n.elts,v);if(O(f,/HX-Trigger-After-Settle:/i)){var r=l;if(!se(l)){r=re().body}_e(f,"HX-Trigger-After-Settle",r)}ie(p)};if(v.settleDelay>0){setTimeout(s,v.settleDelay)}else{s()}}catch(e){fe(l,"htmx:swapError",u);ie(x);throw e}};var b=Q.config.globalViewTransitions;if(v.hasOwnProperty("transition")){b=v.transition}if(b&&ce(l,"htmx:beforeTransition",u)&&typeof Promise!=="undefined"&&document.startViewTransition){var w=new Promise(function(e,t){p=e;x=t});var S=y;y=function(){document.startViewTransition(function(){S();return w})}}if(v.swapDelay>0){setTimeout(y,v.swapDelay)}else{y()}}if(a){fe(l,"htmx:responseError",le({error:"Response Status Error Code "+f.status+" from "+u.pathInfo.requestPath},u))}}var Xr={};function Dr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ur(e,t){if(t.init){t.init(r)}Xr[e]=le(Dr(),t)}function Br(e){delete Xr[e]}function Fr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=te(e,"hx-ext");if(t){oe(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=Xr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return Fr(u(e),r,n)}var Vr=false;re().addEventListener("DOMContentLoaded",function(){Vr=true});function jr(e){if(Vr||re().readyState==="complete"){e()}else{re().addEventListener("DOMContentLoaded",e)}}function _r(){if(Q.config.includeIndicatorStyles!==false){re().head.insertAdjacentHTML("beforeend","")}}function zr(){var e=re().querySelector('meta[name="htmx-config"]');if(e){return E(e.content)}else{return null}}function $r(){var e=zr();if(e){Q.config=le(Q.config,e)}}jr(function(){$r();_r();var e=re().body;zt(e);var t=re().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=ae(t);if(r&&r.xhr){r.xhr.abort()}});const r=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){ar();oe(t,function(e){ce(e,"htmx:restored",{document:re(),triggerEvent:ce})})}else{if(r){r(e)}}};setTimeout(function(){ce(e,"htmx:load",{});e=null},0)});return Q}()}); \ No newline at end of file diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..e69de29