package main import ( "embed" "html/template" "io" "log" "net/http" ) //go:embed views/*.html var tmplFS embed.FS //go:embed public/* var publicFS embed.FS type Template struct { templates *template.Template } func New() *Template { templates := template.Must(template.New("").ParseFS(tmplFS, "views/*.html")) return &Template{ templates: templates, } } func (t *Template) Render(w io.Writer, name string, data any) error { tmpl := template.Must(t.templates.Clone()) tmpl = template.Must(tmpl.ParseFS(tmplFS, "views/"+name)) return tmpl.ExecuteTemplate(w, "layout.html", data) } type Todo struct { Id string Title string Completed bool } type ViewModel struct { Todos []Todo } func main() { todos := make([]Todo, 0, 10) t := New() http.Handle("/public/", http.FileServer(http.FS(publicFS))) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { vm := ViewModel{ Todos: todos, } err := t.Render(w, "list.html", vm) if err != nil { log.Println(err) } }) http.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } if err := r.ParseForm(); err != nil { w.WriteHeader(http.StatusBadRequest) return } title := r.Form.Get("title") todos = append(todos, Todo{ Title: title, }) w.Header().Set("Location", "/") w.WriteHeader(http.StatusSeeOther) }) log.Print("Running on 8080") log.Fatal(http.ListenAndServe(":8080", nil)) }