diff --git a/internal/notes/notes.go b/internal/notes/notes.go index 060d9f1..3507779 100644 --- a/internal/notes/notes.go +++ b/internal/notes/notes.go @@ -5,19 +5,21 @@ package notes import ( "bytes" "fmt" + "html/template" "log" "os" "path/filepath" "gitea.gwairfelin.com/max/gonotes/internal/conf" "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" ) // Note is the central data structure. It can be Saved, Rendered and Loaded // using the Save, Render and LoadNote functions. type Note struct { Title string - BodyRendered string + BodyRendered template.HTML Body []byte } @@ -34,11 +36,17 @@ func (n *Note) Save() error { // Render the markdown content of the note to HTML func (n *Note) Render() { var buf bytes.Buffer - err := goldmark.Convert(n.Body, &buf) + md := goldmark.New( + goldmark.WithExtensions( + extension.TaskList, + ), + ) + err := md.Convert(n.Body, &buf) if err != nil { log.Fatal(err) } - n.BodyRendered = buf.String() + + n.BodyRendered = template.HTML(buf.String()) } // Load a note from the disk. The path is derived from the title diff --git a/internal/notes/views/views.go b/internal/notes/views/views.go index b52b7f5..16d9d72 100644 --- a/internal/notes/views/views.go +++ b/internal/notes/views/views.go @@ -4,7 +4,9 @@ import ( "html/template" "log" "net/http" + "os" "path/filepath" + "strings" "gitea.gwairfelin.com/max/gonotes/internal/conf" "gitea.gwairfelin.com/max/gonotes/internal/notes" @@ -17,15 +19,16 @@ func GetRoutes(prefix string) *http.ServeMux { myurls = urls.URLs{ Prefix: prefix, URLs: map[string]urls.URL{ - "view": {Path: "/{note}/", Protocol: "GET", Handler: viewHandler}, - "edit": {Path: "/{note}/edit/", Protocol: "GET", Handler: editHandler}, - "save": {Path: "/{note}/edit/save/", Protocol: "POST", Handler: saveHandler}, + "view": {Path: "/{note}/", Protocol: "GET", Handler: view}, + "edit": {Path: "/{note}/edit/", Protocol: "GET", Handler: edit}, + "save": {Path: "/{note}/edit/save/", Protocol: "POST", Handler: save}, + "list": {Path: "/", Protocol: "GET", Handler: list}, }, } return myurls.GetRouter() } -func viewHandler(w http.ResponseWriter, r *http.Request) { +func view(w http.ResponseWriter, r *http.Request) { title := r.PathValue("note") note, err := notes.LoadNote(title) if err != nil { @@ -36,13 +39,13 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { note.Render() err = renderTemplate(w, "view.html", note) if err != nil { - log.Println(err) + log.Print(err.Error()) http.Error(w, "Couldn't load template", http.StatusInternalServerError) return } } -func editHandler(w http.ResponseWriter, r *http.Request) { +func edit(w http.ResponseWriter, r *http.Request) { title := r.PathValue("note") note, err := notes.LoadNote(title) if err != nil { @@ -51,13 +54,13 @@ func editHandler(w http.ResponseWriter, r *http.Request) { err = renderTemplate(w, "edit.html", note) if err != nil { - log.Println(err) + log.Print(err.Error()) http.Error(w, "Couldn't load template", http.StatusInternalServerError) return } } -func saveHandler(w http.ResponseWriter, r *http.Request) { +func save(w http.ResponseWriter, r *http.Request) { title := r.PathValue("note") body := r.FormValue("body") note := ¬es.Note{Title: title, Body: []byte(body)} @@ -65,8 +68,37 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, myurls.Reverse("view", map[string]string{"note": title}), http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, note *notes.Note) error { - t, err := template.ParseFiles(filepath.Join(conf.Conf.TemplatesDir, tmpl)) - t.Execute(w, note) +func list(w http.ResponseWriter, r *http.Request) { + files, err := os.ReadDir(conf.Conf.NotesDir) + if err != nil { + log.Print(err.Error()) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + titles := make([]string, 0) + + for _, f := range files { + if !f.IsDir() { + title := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) + titles = append(titles, title) + } + } + + err = renderTemplate(w, "list.tmpl.html", map[string]any{"titles": titles}) + if err != nil { + log.Print(err.Error()) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } +} + +func renderTemplate(w http.ResponseWriter, tmpl string, context any) error { + files := []string{ + filepath.Join(conf.Conf.TemplatesDir, "base.tmpl.html"), + filepath.Join(conf.Conf.TemplatesDir, tmpl), + } + t, err := template.ParseFiles(files...) + t.ExecuteTemplate(w, "base", context) return err } diff --git a/templates/base.tmpl.html b/templates/base.tmpl.html new file mode 100644 index 0000000..901a96d --- /dev/null +++ b/templates/base.tmpl.html @@ -0,0 +1,36 @@ +{{define "base"}} + + + + + + {{template "title" .}} + + + + +
+
+
+

{{template "title" .}}

+
+ {{template "main" .}} +
+
+
+
+ + +{{end}} diff --git a/templates/edit.html b/templates/edit.html index 80a1b49..a19594b 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -1,6 +1,27 @@ -

Editing {{.Title}}

+{{define "title"}}Edit {{.Title}}{{end}} +{{define "main"}}
- - +
+ +
+ +
Enter your note content in markdown
+
+
+ + + + +{{end}} diff --git a/templates/list.tmpl.html b/templates/list.tmpl.html new file mode 100644 index 0000000..908d784 --- /dev/null +++ b/templates/list.tmpl.html @@ -0,0 +1,10 @@ +{{define "title"}}All Notes{{end}} +{{define "main"}} + +{{end}} diff --git a/templates/view.html b/templates/view.html index 59e2cce..adb79ed 100644 --- a/templates/view.html +++ b/templates/view.html @@ -1,3 +1,10 @@ -

{{.Title}}

+{{define "title"}}{{.Title}}{{end}} +{{define "main"}} +
+{{.BodyRendered}} +
+
+ Edit +
+{{end}} -
{{printf "%s" .BodyRendered}}