package web import ( "errors" "fmt" "html/template" "log" "net/http" "net/url" "path/filepath" "strconv" "strings" ) type ( gen map[string]any ) var ( counter int = 1 ) func getContacts() gen { return gen{ "Joe": "joe@example.com", "Sarah": "sarah@example.com", "Fred": "fred@example.com", } } func makeContacts1(templates *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { templates.ExecuteTemplate(w, "contacts", gen{ "contacts": getContacts(), "counter": counter, }) counter++ } } func makeNav(templates *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { path := strings.SplitAfterN(r.URL.Path, "/", 3)[2] htmlPath := r.Header.Get("Hx-Current-Url") u, err := url.Parse(htmlPath) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } htmlPath = strings.SplitAfterN(u.Path, "/", 2)[1] htmlPath = htmlPath[0 : len(htmlPath)-len(filepath.Ext(htmlPath))] num, err := strconv.Atoi(htmlPath) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } switch path { case "nav": templates.ExecuteTemplate(w, "nav", gen{ "num": num, "prev": fmt.Sprintf("%02d", num-1), "curr": fmt.Sprintf("%2d", num), "next": fmt.Sprintf("%02d", num+1), }) default: http.Error(w, path, http.StatusNotFound) return } } } func makeSearch4(templates *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { q := r.FormValue("q") state := r.FormValue("state") raw := getContacts() filtered := gen{} for k, v := range raw { if strings.Contains(strings.ToUpper(k), strings.ToUpper(q)) { filtered[k] = v } } templates.ExecuteTemplate(w, "contacts", gen{ "contacts": filtered, "state": state, }) } } func makeMessages(templates *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { message := r.FormValue("message") log.Printf("%s %s: %q", r.Method, r.URL.Path, message) if err := templates.ExecuteTemplate(w, "messages", gen{ "message": message, }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } } func makeSettings(templates *template.Template) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := templates.ExecuteTemplate(w, "settings", gen{ "text1": "some value for text1", }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } } func SetupRoutes(mux *http.ServeMux, templates *template.Template) { mux.Handle("/", http.FileServer(http.Dir("./web/public/"))) mux.HandleFunc("/autonum/", makeNav(templates)) mux.HandleFunc("/contacts", makeContacts1(templates)) mux.HandleFunc("/messages", makeMessages(templates)) mux.HandleFunc("/search", makeSearch4(templates)) mux.HandleFunc("/settings", makeSettings(templates)) } func UI(addr string) error { templates := template.Must(template.ParseGlob("./web/templates/*.gohtml")) mux := http.NewServeMux() SetupRoutes(mux, templates) if err := http.ListenAndServe(addr, mux); err != nil { if !errors.Is(err, http.ErrServerClosed) { return fmt.Errorf("http server error %w", err) } } return nil }