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")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Todo")
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"));