filtering and toggling

master
Jason Staten 2 years ago
parent ad34ae002a
commit 52374088df

@ -5,7 +5,9 @@ import (
"html/template"
"io"
"log"
"math/rand"
"net/http"
"strconv"
)
//go:embed views/*.html
@ -40,6 +42,19 @@ type Todo struct {
type ViewModel struct {
Todos []Todo
Only string
}
func filterSlice[T any](xs []T, pred func(T) bool) []T {
result := make([]T, 0, len(xs))
for _, element := range xs {
if pred(element) {
result = append(result, element)
}
}
return result
}
func main() {
@ -48,8 +63,21 @@ func main() {
t := New()
http.Handle("/public/", http.FileServer(http.FS(publicFS)))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
renderTodos := todos
only := q.Get("only")
if only == "active" {
renderTodos = filterSlice(todos, func(todo Todo) bool { return !todo.Completed })
}
if only == "completed" {
renderTodos = filterSlice(todos, func(todo Todo) bool { return todo.Completed })
}
vm := ViewModel{
Todos: todos,
Todos: renderTodos,
Only: only,
}
err := t.Render(w, "list.html", vm)
if err != nil {
@ -69,12 +97,36 @@ func main() {
title := r.Form.Get("title")
todos = append(todos, Todo{
Id: strconv.Itoa(rand.Int()),
Title: title,
})
w.Header().Set("Location", "/")
w.WriteHeader(http.StatusSeeOther)
})
http.HandleFunc("/toggle", 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
}
id := r.Form.Get("id")
for i, todo := range todos {
if todo.Id == id {
todo.Completed = !todo.Completed
todos[i] = todo
}
}
w.Header().Set("Location", "/")
w.WriteHeader(http.StatusSeeOther)
})
log.Print("Running on 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

@ -192,6 +192,11 @@ body {
appearance: none;
}
.todo-list li .toggle > button {
width: 40px;
height: 40px;
}
.todo-list li .toggle {
opacity: 0;
}
@ -206,7 +211,7 @@ body {
background-position: center left;
}
.todo-list li .toggle:checked + label {
.todo-list li.completed .toggle + label {
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%2359A193%22%20stroke-width%3D%223%22%2F%3E%3Cpath%20fill%3D%22%233EA390%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22%2F%3E%3C%2Fsvg%3E');
}

@ -1,6 +1,11 @@
<li class="{{if .Completed}}completed{{end}}">
<div class="view">
<input class="toggle" type="checkbox" {{if .Completed}}checked{{end}}>
<form class="toggle" action="/toggle?id={{.Id}}" method="POST">
<button>
t
</button>
</form>
<!-- <input class="toggle" type="checkbox" {{if .Completed}}checked{{end}}> -->
<label>{{.Title}}</label>
<button class="destroy"></button>
</div>

@ -24,13 +24,13 @@
<!-- Remove this if you don't implement routing -->
<ul class="filters">
<li>
<a class="selected" href="#/">All</a>
<a class="{{if eq .Only ""}}selected{{end}}" href="/">All</a>
</li>
<li>
<a href="#/active">Active</a>
<a class="{{if eq .Only "active"}}selected{{end}}" href="/?only=active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
<a class="{{if eq .Only "completed"}}selected{{end}}" href="/?only=completed">Completed</a>
</li>
</ul>
<!-- Hidden if no completed items are left ↓ -->

Loading…
Cancel
Save