Add option to show/hide completed items

This commit is contained in:
Cameron Reed 2024-09-05 18:21:52 -06:00
parent d14d1ec468
commit e96bbdb0dd
7 changed files with 35 additions and 19 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
test.db test.db
todo-web

View File

@ -102,7 +102,7 @@ func GetAllTodos() ([]types.Todo, error) {
func GetOverdueTodos() ([]types.Todo, error) { func GetOverdueTodos() ([]types.Todo, error) {
var todos []types.Todo 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 { if err != nil {
return nil, err return nil, err
} }
@ -136,7 +136,7 @@ func GetTodayTodos() ([]types.Todo, error) {
now := time.Now() now := time.Now()
year, month, day := now.Date() year, month, day := now.Date()
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local) 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 { if err != nil {
return nil, err return nil, err
} }
@ -169,7 +169,7 @@ func GetUpcomingTodos() ([]types.Todo, error) {
year, month, day := time.Now().Date() year, month, day := time.Now().Date()
today := time.Date(year, month, day, 0, 0, 0, 0, time.Local) 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -15,6 +15,7 @@ func main() {
db_path := flag.String("db", "./test.db", "Path to the sqlite3 database") db_path := flag.String("db", "./test.db", "Path to the sqlite3 database")
bind_port := flag.Int("p", 8080, "Port to bind to") bind_port := flag.Int("p", 8080, "Port to bind to")
bind_addr := flag.String("a", "0.0.0.0", "Address 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") noFront := flag.Bool("no-frontend", false, "Disable the frontend endpoints")
a := false; noBack := &a // flag.Bool("no-backend", false, "Disable the backend endpoints") a := false; noBack := &a // flag.Bool("no-backend", false, "Disable the backend endpoints")
@ -28,7 +29,7 @@ func main() {
} }
if !*noFront { if !*noFront {
addFrontendEndpoints(mux) addFrontendEndpoints(mux, *static_dir)
} }
if !*noBack { 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") fmt.Println("Frontend enabled")
mux.HandleFunc("/", Error404) mux.HandleFunc("/", Error404)
@ -64,7 +65,7 @@ func addFrontendEndpoints(mux *http.ServeMux) {
mux.HandleFunc("PUT /update", pages.UpdateItem) mux.HandleFunc("PUT /update", pages.UpdateItem)
mux.HandleFunc("POST /new", pages.CreateItem) 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("/css/", fileServer)
mux.Handle("/js/", fileServer) mux.Handle("/js/", fileServer)
} }

View File

@ -8,7 +8,7 @@ import (
templ RootPage() { templ RootPage() {
<!Doctype HTML> <!Doctype HTML>
<html lang="en-US"> <html lang="en-US" data-show-completed="false">
<head> <head>
<title>Todo</title> <title>Todo</title>
@ -30,7 +30,10 @@ templ RootPage() {
<a id="new-button" href="#create-item">New</a> <a id="new-button" href="#create-item">New</a>
</div> </div>
<div id="nav-center"></div> <div id="nav-center"></div>
<div id="nav-right"></div> <div id="nav-right">
<label for="show-completed">Show completed</label>
<input id="show-completed" type="checkbox" name="show-completed"/>
</div>
</div> </div>
</nav> </nav>

View File

@ -32,7 +32,7 @@ func RootPage() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent templ_7745c5c3_Var1 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype HTML><html lang=\"en-US\"><head><title>Todo</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><link rel=\"stylesheet\" href=\"/css/styles.css\"><script src=\"/js/script.js\"></script><script src=\"/js/lib/htmx.min.js\"></script><!-- Font Awesome --><script src=\"https://kit.fontawesome.com/469cdddb31.js\" crossorigin=\"anonymous\"></script></head><body><nav><div id=\"nav-container\"><div id=\"nav-left\"><a id=\"new-button\" href=\"#create-item\">New</a></div><div id=\"nav-center\"></div><div id=\"nav-right\"></div></div></nav><div id=\"main-content\"><div id=\"lists\"><div id=\"overdue-list\" class=\"todo-list\"><div class=\"todo-list-title\">Overdue</div><div class=\"todo-list-items\" hx-get=\"/overdue\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div><div id=\"today-list\" class=\"todo-list\"><div class=\"todo-list-title\">Today</div><div class=\"todo-list-items\" hx-get=\"/today\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div><div id=\"upcoming-list\" class=\"todo-list\"><div class=\"todo-list-title\">Upcoming</div><div class=\"todo-list-items\" hx-get=\"/upcoming\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div></div><form id=\"create-item\" hx-post=\"/new\" hx-swap=\"none\"><div class=\"form-title\">Create new Todo</div><div class=\"form-container\"><div class=\"form-column\"><label for=\"name\">Name</label><br><input id=\"create-item-name\" type=\"text\" name=\"name\"><br><label for=\"start\">Start</label><br><input id=\"create-item-start\" name=\"start\" type=\"datetime-local\"><br><label for=\"due\">Due</label><br><input id=\"create-item-due\" name=\"due\" type=\"datetime-local\"></div><div class=\"form-column\"></div></div><div class=\"form-button-container\"><button id=\"create-save\" class=\"form-save-button button\" type=\"submit\">Save</button> <a class=\"form-close-button button\" href=\"#\">Close</a></div></form><form id=\"edit-item\" data-id=\"\" hx-put=\"/update\" hx-swap=\"outerHTML\"><div class=\"form-title\">Edit Todo</div><div class=\"form-container\"><div class=\"form-column\"><label for=\"name\">Name</label><br><input id=\"edit-item-name\" type=\"text\" name=\"name\"><br><label for=\"start\">Start</label><br><input id=\"edit-item-start\" name=\"start\" type=\"datetime-local\"><br><label for=\"due\">Due</label><br><input id=\"edit-item-due\" name=\"due\" type=\"datetime-local\"></div><div class=\"form-column\"></div></div><div class=\"form-button-container\"><button id=\"edit-save\" class=\"form-save-button button\" type=\"submit\">Save</button> <a class=\"form-close-button button\" href=\"#\">Close</a></div></form></div></body></html>") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype HTML><html lang=\"en-US\" data-show-completed=\"false\"><head><title>Todo</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><link rel=\"stylesheet\" href=\"/css/styles.css\"><script src=\"/js/script.js\"></script><script src=\"/js/lib/htmx.min.js\"></script><!-- Font Awesome --><script src=\"https://kit.fontawesome.com/469cdddb31.js\" crossorigin=\"anonymous\"></script></head><body><nav><div id=\"nav-container\"><div id=\"nav-left\"><a id=\"new-button\" href=\"#create-item\">New</a></div><div id=\"nav-center\"></div><div id=\"nav-right\"><label for=\"show-completed\">Show completed</label> <input id=\"show-completed\" type=\"checkbox\" name=\"show-completed\"></div></div></nav><div id=\"main-content\"><div id=\"lists\"><div id=\"overdue-list\" class=\"todo-list\"><div class=\"todo-list-title\">Overdue</div><div class=\"todo-list-items\" hx-get=\"/overdue\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div><div id=\"today-list\" class=\"todo-list\"><div class=\"todo-list-title\">Today</div><div class=\"todo-list-items\" hx-get=\"/today\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div><div id=\"upcoming-list\" class=\"todo-list\"><div class=\"todo-list-title\">Upcoming</div><div class=\"todo-list-items\" hx-get=\"/upcoming\" hx-trigger=\"load\" hx-swap=\"outerHTML\"></div><div class=\"new-item\"></div></div></div><form id=\"create-item\" hx-post=\"/new\" hx-swap=\"none\"><div class=\"form-title\">Create new Todo</div><div class=\"form-container\"><div class=\"form-column\"><label for=\"name\">Name</label><br><input id=\"create-item-name\" type=\"text\" name=\"name\"><br><label for=\"start\">Start</label><br><input id=\"create-item-start\" name=\"start\" type=\"datetime-local\"><br><label for=\"due\">Due</label><br><input id=\"create-item-due\" name=\"due\" type=\"datetime-local\"></div><div class=\"form-column\"></div></div><div class=\"form-button-container\"><button id=\"create-save\" class=\"form-save-button button\" type=\"submit\">Save</button> <a class=\"form-close-button button\" href=\"#\">Close</a></div></form><form id=\"edit-item\" data-id=\"\" hx-put=\"/update\" hx-swap=\"outerHTML\"><div class=\"form-title\">Edit Todo</div><div class=\"form-container\"><div class=\"form-column\"><label for=\"name\">Name</label><br><input id=\"edit-item-name\" type=\"text\" name=\"name\"><br><label for=\"start\">Start</label><br><input id=\"edit-item-start\" name=\"start\" type=\"datetime-local\"><br><label for=\"due\">Due</label><br><input id=\"edit-item-due\" name=\"due\" type=\"datetime-local\"></div><div class=\"form-column\"></div></div><div class=\"form-button-container\"><button id=\"edit-save\" class=\"form-save-button button\" type=\"submit\">Save</button> <a class=\"form-close-button button\" href=\"#\">Close</a></div></form></div></body></html>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -75,7 +75,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var3 string var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("item-%d", item.Id)) templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("item-%d", item.Id))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -88,7 +88,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var4 string var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Id)) templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Id))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -101,7 +101,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var5 string var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Start)) templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Start))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -114,7 +114,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var6 string var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Due)) templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", item.Due))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -137,7 +137,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var7 string var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(templ.URL(fmt.Sprintf("/set/%d", item.Id)))) templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(templ.URL(fmt.Sprintf("/set/%d", item.Id))))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -150,7 +150,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Text) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(item.Text)
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -163,7 +163,7 @@ func TodoItem(item types.Todo) templ.Component {
var templ_7745c5c3_Var9 string var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/delete/%d", item.Id)) templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/delete/%d", item.Id))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -202,7 +202,7 @@ func OobTodoItem(targetSelector string, item types.Todo) templ.Component {
var templ_7745c5c3_Var11 string var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s:%s", "afterend", targetSelector)) templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s:%s", "afterend", targetSelector))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -249,7 +249,7 @@ func TodoList(fillerText string, items []types.Todo) templ.Component {
var templ_7745c5c3_Var13 string var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(items))) templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(items)))
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -262,7 +262,7 @@ func TodoList(fillerText string, items []types.Todo) templ.Component {
var templ_7745c5c3_Var14 string var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fillerText) templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fillerText)
if templ_7745c5c3_Err != nil { 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)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -13,6 +13,7 @@ nav {
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
} }
#new-button { #new-button {
@ -107,6 +108,11 @@ nav {
gap: 10px; gap: 10px;
} }
[data-show-completed="false"]
.todo-item:has(input[type="checkbox"]:checked) {
display: none;
}
.todo-text { .todo-text {
flex: 1; flex: 1;
text-wrap: nowrap; text-wrap: nowrap;

View File

@ -66,6 +66,11 @@ function on_load() {
overdue_items.setAttribute("data-item-count", parseInt(overdue_items.getAttribute("data-item-count")) + 1); 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) { document.querySelector("#today-list > .new-item").addEventListener("htmx:oobBeforeSwap", function(evt) {
let today_items = document.querySelector("#today-list > .todo-list-items"); let today_items = document.querySelector("#today-list > .todo-list-items");
let due = parseInt(evt.detail.fragment.firstElementChild.getAttribute("data-due")); let due = parseInt(evt.detail.fragment.firstElementChild.getAttribute("data-due"));