From e96bbdb0dd1ebcb112c37e8a154aaae05f54887c Mon Sep 17 00:00:00 2001 From: Cameron Reed Date: Thu, 5 Sep 2024 18:21:52 -0600 Subject: [PATCH] Add option to show/hide completed items --- .gitignore | 1 + db/db.go | 6 +++--- main.go | 7 ++++--- pages/templates/root.templ | 7 +++++-- pages/templates/root_templ.go | 22 +++++++++++----------- static/css/styles.css | 6 ++++++ static/js/script.js | 5 +++++ 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index c370cb6..2a93830 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ test.db +todo-web diff --git a/db/db.go b/db/db.go index 7d88799..c1e1136 100644 --- a/db/db.go +++ b/db/db.go @@ -102,7 +102,7 @@ func GetAllTodos() ([]types.Todo, error) { func GetOverdueTodos() ([]types.Todo, error) { var todos []types.Todo - rows, err := db.Query("SELECT * FROM items WHERE due < ? AND due IS NOT NULL ORDER BY due", time.Now().Unix()) + rows, err := db.Query("SELECT * FROM items WHERE due < ? AND due IS NOT NULL ORDER BY completed, due", time.Now().Unix()) if err != nil { return nil, err } @@ -136,7 +136,7 @@ func GetTodayTodos() ([]types.Todo, error) { now := time.Now() year, month, day := now.Date() today := time.Date(year, month, day, 0, 0, 0, 0, time.Local) - rows, err := db.Query("SELECT * FROM items WHERE (start <= ? OR start IS NULL) AND (due >= ? OR due IS NULL) ORDER BY due NULLS LAST", today.Unix(), now.Unix()) + rows, err := db.Query("SELECT * FROM items WHERE (start <= ? OR start IS NULL) AND (due >= ? OR due IS NULL) ORDER BY completed, due NULLS LAST", today.Unix(), now.Unix()) if err != nil { return nil, err } @@ -169,7 +169,7 @@ func GetUpcomingTodos() ([]types.Todo, error) { year, month, day := time.Now().Date() today := time.Date(year, month, day, 0, 0, 0, 0, time.Local) - rows, err := db.Query("SELECT * FROM items WHERE start > ? ORDER BY start", today.Unix()) + rows, err := db.Query("SELECT * FROM items WHERE start > ? ORDER BY completed, start", today.Unix()) if err != nil { return nil, err } diff --git a/main.go b/main.go index 3bc259a..1043d3e 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,7 @@ func main() { db_path := flag.String("db", "./test.db", "Path to the sqlite3 database") bind_port := flag.Int("p", 8080, "Port to bind to") bind_addr := flag.String("a", "0.0.0.0", "Address to bind to") + static_dir := flag.String("static", "./static", "Path to static files") noFront := flag.Bool("no-frontend", false, "Disable the frontend endpoints") a := false; noBack := &a // flag.Bool("no-backend", false, "Disable the backend endpoints") @@ -28,7 +29,7 @@ func main() { } if !*noFront { - addFrontendEndpoints(mux) + addFrontendEndpoints(mux, *static_dir) } if !*noBack { @@ -50,7 +51,7 @@ func main() { } } -func addFrontendEndpoints(mux *http.ServeMux) { +func addFrontendEndpoints(mux *http.ServeMux, static_path string) { fmt.Println("Frontend enabled") mux.HandleFunc("/", Error404) @@ -64,7 +65,7 @@ func addFrontendEndpoints(mux *http.ServeMux) { mux.HandleFunc("PUT /update", pages.UpdateItem) mux.HandleFunc("POST /new", pages.CreateItem) - fileServer := http.FileServer(http.Dir("./static")) + fileServer := http.FileServer(http.Dir(static_path)) mux.Handle("/css/", fileServer) mux.Handle("/js/", fileServer) } diff --git a/pages/templates/root.templ b/pages/templates/root.templ index ed0c2b4..517705e 100644 --- a/pages/templates/root.templ +++ b/pages/templates/root.templ @@ -8,7 +8,7 @@ import ( templ RootPage() { - + Todo @@ -30,7 +30,10 @@ templ RootPage() { New - + diff --git a/pages/templates/root_templ.go b/pages/templates/root_templ.go index f17a91f..e8479d0 100644 --- a/pages/templates/root_templ.go +++ b/pages/templates/root_templ.go @@ -32,7 +32,7 @@ func RootPage() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Todo
Overdue
Today
Upcoming
Create new Todo





Close
Edit Todo





Close
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Todo
Overdue
Today
Upcoming
Create new Todo





Close
Edit Todo





Close
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -75,7 +75,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("item-%d", item.Id)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 113, Col: 45} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 116, Col: 45} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -88,7 +88,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Id)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 113, Col: 105} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 116, Col: 105} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -101,7 +101,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Start)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 113, Col: 150} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 116, Col: 150} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -114,7 +114,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Due)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 113, Col: 191} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 116, Col: 191} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -137,7 +137,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(templ.URL(fmt.Sprintf("/set/%d", item.Id)))) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 114, Col: 137} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 117, Col: 137} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -150,7 +150,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Text) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 115, Col: 42} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 118, Col: 42} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { @@ -163,7 +163,7 @@ func TodoItem(item types.Todo) templ.Component { var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/delete/%d", item.Id)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 118, Col: 101} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 121, Col: 101} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { @@ -202,7 +202,7 @@ func OobTodoItem(targetSelector string, item types.Todo) templ.Component { var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s:%s", "afterend", targetSelector)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 124, Col: 71} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 127, Col: 71} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { @@ -249,7 +249,7 @@ func TodoList(fillerText string, items []types.Todo) templ.Component { var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(items))) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 130, Col: 80} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 133, Col: 80} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { @@ -262,7 +262,7 @@ func TodoList(fillerText string, items []types.Todo) templ.Component { var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fillerText) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 131, Col: 45} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `pages/templates/root.templ`, Line: 134, Col: 45} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { diff --git a/static/css/styles.css b/static/css/styles.css index 76d19a7..bac4484 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -13,6 +13,7 @@ nav { margin: 0 auto; display: flex; justify-content: space-between; + align-items: center; } #new-button { @@ -107,6 +108,11 @@ nav { gap: 10px; } +[data-show-completed="false"] +.todo-item:has(input[type="checkbox"]:checked) { + display: none; +} + .todo-text { flex: 1; text-wrap: nowrap; diff --git a/static/js/script.js b/static/js/script.js index db5f811..cac500d 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -66,6 +66,11 @@ function on_load() { overdue_items.setAttribute("data-item-count", parseInt(overdue_items.getAttribute("data-item-count")) + 1); }); + let checkbox = document.getElementById("show-completed"); + checkbox.addEventListener("change", function(evt) { + document.documentElement.setAttribute("data-show-completed", checkbox.checked); + }); + document.querySelector("#today-list > .new-item").addEventListener("htmx:oobBeforeSwap", function(evt) { let today_items = document.querySelector("#today-list > .todo-list-items"); let due = parseInt(evt.detail.fragment.firstElementChild.getAttribute("data-due"));